Giter VIP home page Giter VIP logo

s.el's Introduction

s.el s.el testing Coverage Status

The long lost Emacs string manipulation library.

Installation

It's available on Melpa:

M-x package-install s

Or you can just dump s.el in your load path somewhere.

Functions

Tweak whitespace

To shorter string

To longer string

To and from lists

Predicates

The misc bucket

Pertaining to words

Documentation and examples

s-trim (s)

Remove whitespace at the beginning and end of s.

(s-trim "trim ") ;; => "trim"
(s-trim " this") ;; => "this"
(s-trim " only  trims beg and end  ") ;; => "only  trims beg and end"

s-trim-left (s)

Remove whitespace at the beginning of s.

(s-trim-left "trim ") ;; => "trim "
(s-trim-left " this") ;; => "this"

s-trim-right (s)

Remove whitespace at the end of s.

(s-trim-right "trim ") ;; => "trim"
(s-trim-right " this") ;; => " this"

s-chomp (s)

Remove one trailing \n, \r or \r\n from s.

(s-chomp "no newlines\n") ;; => "no newlines"
(s-chomp "no newlines\r\n") ;; => "no newlines"
(s-chomp "some newlines\n\n") ;; => "some newlines\n"

s-collapse-whitespace (s)

Convert all adjacent whitespace characters to a single space.

(s-collapse-whitespace "only   one space   please") ;; => "only one space please"
(s-collapse-whitespace "collapse \n all \t sorts of \r whitespace") ;; => "collapse all sorts of whitespace"

s-word-wrap (len s)

If s is longer than len, wrap the words with newlines.

(s-word-wrap 10 "This is too long") ;; => "This is\ntoo long"
(s-word-wrap 10 "This is way way too long") ;; => "This is\nway way\ntoo long"
(s-word-wrap 10 "It-wraps-words-but-does-not-break-them") ;; => "It-wraps-words-but-does-not-break-them"

s-center (len s)

If s is shorter than len, pad it with spaces so it is centered.

(s-center 5 "a") ;; => "  a  "
(s-center 5 "ab") ;; => "  ab "
(s-center 1 "abc") ;; => "abc"

s-pad-left (len padding s)

If s is shorter than len, pad it with padding on the left.

(s-pad-left 3 "0" "3") ;; => "003"
(s-pad-left 3 "0" "23") ;; => "023"
(s-pad-left 3 "0" "1234") ;; => "1234"

s-pad-right (len padding s)

If s is shorter than len, pad it with padding on the right.

(s-pad-right 3 "." "3") ;; => "3.."
(s-pad-right 3 "." "23") ;; => "23."
(s-pad-right 3 "." "1234") ;; => "1234"

s-truncate (len s)

If s is longer than len, cut it down to len - 3 and add ... at the end.

(s-truncate 6 "This is too long") ;; => "Thi..."
(s-truncate 16 "This is also too long") ;; => "This is also ..."
(s-truncate 16 "But this is not!") ;; => "But this is not!"

s-left (len s)

Returns up to the len first chars of s.

(s-left 3 "lib/file.js") ;; => "lib"
(s-left 3 "li") ;; => "li"

s-right (len s)

Returns up to the len last chars of s.

(s-right 3 "lib/file.js") ;; => ".js"
(s-right 3 "li") ;; => "li"

s-chop-left (len s)

Remove the first len chars from s.

(s-chop-left 3 "lib/file.js") ;; => "/file.js"
(s-chop-left 3 "li") ;; => ""

s-chop-right (len s)

Remove the last len chars from s.

(s-chop-right 3 "lib/file.js") ;; => "lib/file"
(s-chop-right 3 "li") ;; => ""

s-chop-suffix (suffix s)

Remove suffix if it is at end of s.

(s-chop-suffix "-test.js" "penguin-test.js") ;; => "penguin"
(s-chop-suffix "\n" "no newlines\n") ;; => "no newlines"
(s-chop-suffix "\n" "some newlines\n\n") ;; => "some newlines\n"

s-chop-suffixes (suffixes s)

Remove suffixes one by one in order, if they are at the end of s.

(s-chop-suffixes '("_test.js" "-test.js" "Test.js") "penguin-test.js") ;; => "penguin"
(s-chop-suffixes '("\r" "\n") "penguin\r\n") ;; => "penguin\r"
(s-chop-suffixes '("\n" "\r") "penguin\r\n") ;; => "penguin"

s-chop-prefix (prefix s)

Remove prefix if it is at the start of s.

(s-chop-prefix "/tmp" "/tmp/file.js") ;; => "/file.js"
(s-chop-prefix "/tmp" "/tmp/tmp/file.js") ;; => "/tmp/file.js"

s-chop-prefixes (prefixes s)

Remove prefixes one by one in order, if they are at the start of s.

(s-chop-prefixes '("/tmp" "/my") "/tmp/my/file.js") ;; => "/file.js"
(s-chop-prefixes '("/my" "/tmp") "/tmp/my/file.js") ;; => "/my/file.js"

s-shared-start (s1 s2)

Returns the longest prefix s1 and s2 have in common.

(s-shared-start "bar" "baz") ;; => "ba"
(s-shared-start "foobar" "foo") ;; => "foo"
(s-shared-start "bar" "foo") ;; => ""

s-shared-end (s1 s2)

Returns the longest suffix s1 and s2 have in common.

(s-shared-end "bar" "var") ;; => "ar"
(s-shared-end "foo" "foo") ;; => "foo"
(s-shared-end "bar" "foo") ;; => ""

s-repeat (num s)

Make a string of s repeated num times.

(s-repeat 10 " ") ;; => "          "
(s-concat (s-repeat 8 "Na") " Batman!") ;; => "NaNaNaNaNaNaNaNa Batman!"

s-concat (&rest strings)

Join all the string arguments into one string.

(s-concat "abc" "def" "ghi") ;; => "abcdefghi"

s-prepend (prefix s)

Concatenate prefix and s.

(s-prepend "abc" "def") ;; => "abcdef"

s-append (suffix s)

Concatenate s and suffix.

(s-append "abc" "def") ;; => "defabc"

s-splice (needle n s)

Splice needle into s at position n. 0 is the beginning of the string, -1 is the end.

(s-splice "abc" 0 "def") ;; => "abcdef"
(s-splice "abc" -1 "def") ;; => "defabc"
(s-splice "needle" 2 "A  in a haystack.") ;; => "A needle in a haystack."

s-lines (s)

Splits s into a list of strings on newline characters.

(s-lines "abc\ndef\nghi") ;; => '("abc" "def" "ghi")
(s-lines "abc\rdef\rghi") ;; => '("abc" "def" "ghi")
(s-lines "abc\r\ndef\r\nghi") ;; => '("abc" "def" "ghi")

s-match (regexp s &optional start)

When the given expression matches the string, this function returns a list of the whole matching string and a string for each matched subexpressions. If it did not match the returned value is an empty list (nil).

When start is non-nil the search will start at that index.

(s-match "^def" "abcdefg") ;; => nil
(s-match "^abc" "abcdefg") ;; => '("abc")
(s-match "^/.*/\\([a-z]+\\)\\.\\([a-z]+\\)" "/some/weird/file.html") ;; => '("/some/weird/file.html" "file" "html")

s-match-strings-all (regex string)

Return a list of matches for regex in string.

Each element itself is a list of matches, as per match-string. Multiple matches at the same position will be ignored after the first.

(s-match-strings-all "{\\([^}]+\\)}" "x is {x} and y is {y}") ;; => '(("{x}" "x") ("{y}" "y"))
(s-match-strings-all "ab." "abXabY") ;; => '(("abX") ("abY"))
(s-match-strings-all "\\<" "foo bar baz") ;; => '(("") ("") (""))

s-matched-positions-all (regexp string &optional subexp-depth)

Return a list of matched positions for regexp in string. subexp-depth is 0 by default.

(s-matched-positions-all "l+" "{{Hello}} World, {{Emacs}}!" 0) ;; => '((4 . 6) (13 . 14))
(s-matched-positions-all "{{\\(.+?\\)}}" "{{Hello}} World, {{Emacs}}!" 0) ;; => '((0 . 9) (17 . 26))
(s-matched-positions-all "{{\\(.+?\\)}}" "{{Hello}} World, {{Emacs}}!" 1) ;; => '((2 . 7) (19 . 24))

s-slice-at (regexp s)

Slices s up at every index matching regexp.

(s-slice-at "-" "abc") ;; => '("abc")
(s-slice-at "-" "abc-def") ;; => '("abc" "-def")
(s-slice-at "[.#]" "abc.def.ghi#id") ;; => '("abc" ".def" ".ghi" "#id")

s-split (separator s &optional omit-nulls)

Split s into substrings bounded by matches for regexp separator. If omit-nulls is non-nil, zero-length substrings are omitted.

This is a simple wrapper around the built-in split-string.

(s-split "|" "a|bc|12|3") ;; => '("a" "bc" "12" "3")
(s-split ":" "a,c,d") ;; => '("a,c,d")
(s-split "\n" "z\nefg\n") ;; => '("z" "efg" "")

s-split-up-to (separator s n &optional omit-nulls)

Split s up to n times into substrings bounded by matches for regexp separator.

If omit-nulls is non-nil, zero-length substrings are omitted.

See also s-split.

(s-split-up-to "\\s-*-\\s-*" "Author - Track-number-one" 1) ;; => '("Author" "Track-number-one")
(s-split-up-to "\\s-*-\\s-*" "Author - Track-number-one" 2) ;; => '("Author" "Track" "number-one")
(s-split-up-to "|" "foo||bar|baz|qux" 3 t) ;; => '("foo" "bar" "baz|qux")

s-join (separator strings)

Join all the strings in strings with separator in between.

(s-join "+" '("abc" "def" "ghi")) ;; => "abc+def+ghi"
(s-join "\n" '("abc" "def" "ghi")) ;; => "abc\ndef\nghi"

s-equals? (s1 s2)

Is s1 equal to s2?

This is a simple wrapper around the built-in string-equal.

(s-equals? "abc" "ABC") ;; => nil
(s-equals? "abc" "abc") ;; => t

s-less? (s1 s2)

Is s1 less than s2?

This is a simple wrapper around the built-in string-lessp.

(s-less? "abc" "abd") ;; => t
(s-less? "abd" "abc") ;; => nil
(s-less? "abc" "abc") ;; => nil

s-matches? (regexp s &optional start)

Does regexp match s? If start is non-nil the search starts at that index.

This is a simple wrapper around the built-in string-match-p.

(s-matches? "^[0-9]+$" "123") ;; => t
(s-matches? "^[0-9]+$" "a123") ;; => nil
(s-matches? "1" "1a" 1) ;; => nil

s-blank? (s)

Is s nil or the empty string?

(s-blank? "") ;; => t
(s-blank? nil) ;; => t
(s-blank? " ") ;; => nil

s-present? (s)

Is s anything but nil or the empty string?

(s-present? "") ;; => nil
(s-present? nil) ;; => nil
(s-present? " ") ;; => t

s-ends-with? (suffix s &optional ignore-case)

Does s end with suffix?

If ignore-case is non-nil, the comparison is done without paying attention to case differences.

Alias: s-suffix?

(s-ends-with? ".md" "readme.md") ;; => t
(s-ends-with? ".MD" "readme.md") ;; => nil
(s-ends-with? ".MD" "readme.md" t) ;; => t

s-starts-with? (prefix s &optional ignore-case)

Does s start with prefix?

If ignore-case is non-nil, the comparison is done without paying attention to case differences.

Alias: s-prefix?. This is a simple wrapper around the built-in string-prefix-p.

(s-starts-with? "lib/" "lib/file.js") ;; => t
(s-starts-with? "LIB/" "lib/file.js") ;; => nil
(s-starts-with? "LIB/" "lib/file.js" t) ;; => t

s-contains? (needle s &optional ignore-case)

Does s contain needle?

If ignore-case is non-nil, the comparison is done without paying attention to case differences.

(s-contains? "file" "lib/file.js") ;; => t
(s-contains? "nope" "lib/file.js") ;; => nil
(s-contains? "^a" "it's not ^a regexp") ;; => t

s-lowercase? (s)

Are all the letters in s in lower case?

(s-lowercase? "file") ;; => t
(s-lowercase? "File") ;; => nil
(s-lowercase? "filä") ;; => t

s-uppercase? (s)

Are all the letters in s in upper case?

(s-uppercase? "HULK SMASH") ;; => t
(s-uppercase? "Bruce no smash") ;; => nil
(s-uppercase? "FöB") ;; => nil

s-mixedcase? (s)

Are there both lower case and upper case letters in s?

(s-mixedcase? "HULK SMASH") ;; => nil
(s-mixedcase? "Bruce no smash") ;; => t
(s-mixedcase? "BRÜCE") ;; => nil

s-capitalized? (s)

In s, is the first letter upper case, and all other letters lower case?

(s-capitalized? "Capitalized") ;; => t
(s-capitalized? "I am capitalized") ;; => t
(s-capitalized? "I Am Titleized") ;; => nil

s-numeric? (s)

Is s a number?

(s-numeric? "123") ;; => t
(s-numeric? "onetwothree") ;; => nil
(s-numeric? "7a") ;; => nil

s-replace (old new s)

Replaces old with new in s.

(s-replace "file" "nope" "lib/file.js") ;; => "lib/nope.js"
(s-replace "^a" "\\1" "it's not ^a regexp") ;; => "it's not \\1 regexp"

s-replace-all (replacements s)

replacements is a list of cons-cells. Each car is replaced with cdr in s.

(s-replace-all '(("lib" . "test") ("file" . "file_test")) "lib/file.js") ;; => "test/file_test.js"
(s-replace-all '(("lib" . "test") ("test" . "lib")) "lib/test.js") ;; => "test/lib.js"

s-downcase (s)

Convert s to lower case.

This is a simple wrapper around the built-in downcase.

(s-downcase "ABC") ;; => "abc"

s-upcase (s)

Convert s to upper case.

This is a simple wrapper around the built-in upcase.

(s-upcase "abc") ;; => "ABC"

s-capitalize (s)

Convert the first word's first character to upper case and the rest to lower case in s.

(s-capitalize "abc DEF") ;; => "Abc def"
(s-capitalize "abc.DEF") ;; => "Abc.def"

s-titleize (s)

Convert each word's first character to upper case and the rest to lower case in s.

This is a simple wrapper around the built-in capitalize.

(s-titleize "abc DEF") ;; => "Abc Def"
(s-titleize "abc.DEF") ;; => "Abc.Def"

s-with (s form &rest more)

Threads s through the forms. Inserts s as the last item in the first form, making a list of it if it is not a list already. If there are more forms, inserts the first form as the last item in second form, etc.

(s-with "   hulk smash   " s-trim s-upcase) ;; => "HULK SMASH"
(s-with "My car is a Toyota" (s-replace "car" "name") (s-replace "a Toyota" "Bond") (s-append ", James Bond")) ;; => "My name is Bond, James Bond"
(s-with "abc \ndef  \nghi" s-lines (mapcar 's-trim) (s-join "-") s-reverse) ;; => "ihg-fed-cba"

s-index-of (needle s &optional ignore-case)

Returns first index of needle in s, or nil.

If ignore-case is non-nil, the comparison is done without paying attention to case differences.

(s-index-of "abc" "abcdef") ;; => 0
(s-index-of "CDE" "abcdef" t) ;; => 2
(s-index-of "n.t" "not a regexp") ;; => nil

s-reverse (s)

Return the reverse of s.

(s-reverse "abc") ;; => "cba"
(s-reverse "ab xyz") ;; => "zyx ba"
(s-reverse "") ;; => ""

s-presence (s)

Return s if it's s-present?, otherwise return nil.

(s-presence nil) ;; => nil
(s-presence "") ;; => nil
(s-presence "foo") ;; => "foo"

s-format (template replacer &optional extra)

Format template with the function replacer.

replacer takes an argument of the format variable and optionally an extra argument which is the extra value from the call to s-format.

Several standard s-format helper functions are recognized and adapted for this:

(s-format "${name}" 'gethash hash-table)
(s-format "${name}" 'aget alist)
(s-format "$0" 'elt sequence)

The replacer function may be used to do any other kind of transformation.

(s-format "help ${name}! I'm ${malady}" 'aget '(("name" . "nic") ("malady" . "on fire"))) ;; => "help nic! I'm on fire"
(s-format "hello ${name}, nice day" (lambda (var-name) "nic")) ;; => "hello nic, nice day"
(s-format "hello $0, nice $1" 'elt '("nic" "day")) ;; => "hello nic, nice day"

s-lex-format (format-str)

s-format with the current environment.

format-str may use the s-format variable reference to refer to any variable:

(let ((x 1)) (s-lex-format "x is: ${x}"))

The values of the variables are interpolated with "%s" unless the variable s-lex-value-as-lisp is t and then they are interpolated with "%S".

(let ((x 1)) (s-lex-format "x is ${x}")) ;; => "x is 1"
(let ((str1 "this") (str2 "that")) (s-lex-format "${str1} and ${str2}")) ;; => "this and that"
(let ((foo "Hello\\nWorld")) (s-lex-format "${foo}")) ;; => "Hello\\nWorld"

s-count-matches (regexp s &optional start end)

Count occurrences of regexp in `s'.

start, inclusive, and end, exclusive, delimit the part of s to match.

(s-count-matches "a" "aba") ;; => 2
(s-count-matches "a" "aba" 0 2) ;; => 1
(s-count-matches "\\w\\{2\\}[0-9]+" "ab1bab2frobinator") ;; => 2

s-wrap (s prefix &optional suffix)

Wrap string s with prefix and optionally suffix.

Return string s with prefix prepended. If suffix is present, it is appended, otherwise prefix is used as both prefix and suffix.

(s-wrap "foo" "\"") ;; => "\"foo\""
(s-wrap "foo" "(" ")") ;; => "(foo)"
(s-wrap "foo" "bar") ;; => "barfoobar"

s-split-words (s)

Split s into list of words.

(s-split-words "under_score") ;; => '("under" "score")
(s-split-words "some-dashed-words") ;; => '("some" "dashed" "words")
(s-split-words "evenCamelCase") ;; => '("even" "Camel" "Case")

s-lower-camel-case (s)

Convert s to lowerCamelCase.

(s-lower-camel-case "some words") ;; => "someWords"
(s-lower-camel-case "dashed-words") ;; => "dashedWords"
(s-lower-camel-case "under_scored_words") ;; => "underScoredWords"

s-upper-camel-case (s)

Convert s to UpperCamelCase.

(s-upper-camel-case "some words") ;; => "SomeWords"
(s-upper-camel-case "dashed-words") ;; => "DashedWords"
(s-upper-camel-case "under_scored_words") ;; => "UnderScoredWords"

s-snake-case (s)

Convert s to snake_case.

(s-snake-case "some words") ;; => "some_words"
(s-snake-case "dashed-words") ;; => "dashed_words"
(s-snake-case "camelCasedWords") ;; => "camel_cased_words"

s-dashed-words (s)

Convert s to dashed-words.

(s-dashed-words "some words") ;; => "some-words"
(s-dashed-words "under_scored_words") ;; => "under-scored-words"
(s-dashed-words "camelCasedWords") ;; => "camel-cased-words"

s-capitalized-words (s)

Convert s to Capitalized words.

(s-capitalized-words "some words") ;; => "Some words"
(s-capitalized-words "under_scored_words") ;; => "Under scored words"
(s-capitalized-words "camelCasedWords") ;; => "Camel cased words"

s-titleized-words (s)

Convert s to Titleized Words.

(s-titleized-words "some words") ;; => "Some Words"
(s-titleized-words "under_scored_words") ;; => "Under Scored Words"
(s-titleized-words "camelCasedWords") ;; => "Camel Cased Words"

s-word-initials (s)

Convert s to its initials.

(s-word-initials "some words") ;; => "sw"
(s-word-initials "under_scored_words") ;; => "usw"
(s-word-initials "camelCasedWords") ;; => "cCW"

s-blank-str? (s)

Is s nil or the empty string or string only contains whitespace?

(s-blank-str? "  \t \r   ") ;; => t
(s-blank-str? "    ") ;; => t
(s-blank-str? "\t\r") ;; => t

What's with the built-in wrappers?

Imagine looking through the function list and seeing s-ends-with?, but s-starts-with? is nowhere to be found. Why? Well, because Emacs already has string-prefix-p. Now you're starting out slightly confused, then have to go somewhere else to dig for the command you were looking for.

The wrapping functions serve as both documentation for existing functions and makes for a consistent API.

Other string related libraries

  • inflections package provides functions for strings pluralization and singularization.

  • levenshtein package provides a function to calculate the Levenshtein distance between two strings.

  • string-utils is another general string manipulation library.

Changelist

From 1.11.0 to 1.12.0

  • Alias all functions ending in ? (Tianxiang Xiong)
  • Add s-blank-str? (Aborn Jiang)
  • Several bugfixes

From 1.10.0 to 1.11.0

  • Add s-matched-positions-all (ono hiroko)

From 1.9.0 to 1.10.0

  • Add s-wrap (Johan Andersson)
  • Add s-split-up-to (Matus Goljer)
  • Fix s-reverse for Unicode combining characters. (Christopher Wellons)

From 1.8.0 to 1.9.0

  • Add s-count-matches (Lars Andersen)

From 1.7.0 to 1.8.0

  • Add s-present? and s-present? (Johan Andersson)
  • Better handling of international characters

From 1.6.0 to 1.7.0

  • Add s-word-initials (Sylvain Rousseau)
  • Better handling of camel cased strings (@Bruce-Connor)

From 1.5.0 to 1.6.0

  • Add s-pad-left and s-pad-right
  • Bugfixes for s-format (Nic Ferrier)

From 1.4.0 to 1.5.0

  • Add s-all-match-strings (Geoff Gole)
  • Add s-lex-format (Nic Ferrier)

From 1.3.1 to 1.4.0

  • Add s-capitalized?
  • Add s-replace-all
  • Add s-slice-at
  • Add s-split alias for split-string (Rüdiger Sonderfeld)
  • Add s-less? predicate (Rüdiger Sonderfeld)
  • Add START parameter to s-matches? (Rüdiger Sonderfeld)
  • Bugfixes

From 1.3.0 to 1.3.1

  • Add s-numeric?
  • Add s-match (Arthur Andersen)
  • Add s-format (Nic Ferrier)
  • Move .el files out of root to avoid problems with require.

From 1.2.1 to 1.3.0

  • Breaking change: s-capitalize now converts the first word's first character to upper case and the rest to lower case. s-titleize works like the old s-capitalize and capitalizes each word. (Johan Andersson)

  • s-capitalized-words and s-titleized-words mirror this change.

Contributors

Thanks!

Contribute

Yes, please do. Pure functions in the string manipulation realm only, please. There's a suite of tests in dev/examples.el, so remember to add tests for your function, or I might break it later.

You'll find the repo at:

https://github.com/magnars/s.el

Run the tests with

./run-tests.sh

Create the docs with

./create-docs.sh

I highly recommend that you install these as a pre-commit hook, so that the tests are always running and the docs are always in sync:

cp pre-commit.sh .git/hooks/pre-commit

Oh, and don't edit README.md directly, it is auto-generated. Change readme-template.md or examples-to-docs.el instead.

License

Copyright (C) 2012-2022 Magnar Sveen

Authors: Magnar Sveen [email protected] Maintainer: Jason Milkins [email protected] Keywords: strings

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

s.el's People

Contributors

aborn avatar basil-conto avatar cy20lin avatar dr-scsi avatar eigengrau avatar expez avatar fuco1 avatar gsg avatar jasonm23 avatar kuanyui avatar lujun9972 avatar magnars avatar malabarba avatar nicferrier avatar odanoburu avatar phst avatar ptrv avatar purcell avatar rejeep avatar rolpereira avatar ruediger avatar sachac avatar silex avatar swsnr avatar syohex avatar tarsius avatar thisirs avatar wilfred avatar xiongtx avatar zck avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

s.el's Issues

s-reverse doesn't implement extended grapheme clusters

For example

(equal (s-reverse "g\u0308각각กநிเกำषि") "षिกำเநிก각각g\u0308")

is nil, but should be t. Rather, s-reverse should implement extended grapheme clusters from http://unicode.org/reports/tr29/.
That's probably too much work without support from Emacs, so I check whether I can get extended grapheme cluster support into Emacs in some form.

s-replace-regex?

Hello,

Hum, I was surprised not to find this function (or s-replace-all-regex).

Is this intentional? I'll use replace-regexp-in-string in the meantime but I think it would make a nice addition :)

make some function destructive

I found it's no pros to use some s- functions compare to native ones, like: s-append compare to concat

Like some elisp functions, like sort ncons, people use it for it's simplify the modification.

So my proposal is to make some functions (maybe new ones) with modification feature, like:

(s-append-it ";" s)  ; will modify s

That way user can enjoy it than using native one: (setq s (concat s ";"))

[discussion] Add functions for manipulation of text properties?

Is this something that would fit the library? Do we want it to be only string manipulation or emacs string manipulation. Text properties are very central to how emacs works with text, so I think it would fit all right, but maybe someone has a different opinion?

The emacs api for this is, as usual, absolutely terrible. There's also a bunch of very useful functions in gnus namespace (as usual :D) which could be ported too (also notmuch, eimp, org, message,dired`... really, this is insane)

Maybe we can do it the same way as with dash-functional, leaving it in the same repo, but a separate file, for example stp.el (s-text-properties).

Discuss.

Emacs integration

This library is so important that there is no reason for it to be external to Emacs.

Please integrate these functions into Emacs.

Call interactively

Hey everyone,

I'm interested in using these functions interactively.

In a dream world, I'd love to bind these to some sweet hotkeys, mark a region and be able to quickly camelCase some text. Basically, I'd like the exact same flow as evil-upcase, but with all of the amazing functions provided by s.el.

I'm looking for guidance in one of the following ways:

Make a PR?

I imagine if I were to make a PR, it would involve implementing a helper for each of these using call-interactively like in https://www.gnu.org/software/emacs/manual/html_node/elisp/Interactive-Call.html

That seems inefficient / not how it should be done

Use another package?

Maybe there is something else out there that does this already for me. Maybe you all know of this package.

Something I'm not thinking of?

<3 Side note: I'm a spacemacs user <3

Wrap existing string functions

I find it annoying to use functions coming from two libraries, so I think it would be best to wrap the core string functions in s.el as well for the sake of consistency. It would be nice to have s-upcase, s-downcase, s-equal... I guess you get the picture. Thoughts?

feature request: add function inverse to `string-to-list`.

Add a function inverse to string-to-list.

Currently, one must do (apply 'string list) which is less than ideal in case we want to map or compose the (proposed, non existing) list-to-string function.

Could be called s-list-to-string or just s-to-string.

Awesome task for beginners :) !!!

s-concat or concat

I don't understand the point of s-concat because we already have concat which looks to have similar behavior.

Create s-edit

Please create s-edit function so that string may be edited and returned with new value.

case-sensitive s-format

Hi,

s-format seems to have a strange behavior for upper case string variables.

Whereas a lower case variable result in a properly cased replacement.

(s-format "help ${name}! I'm ${malady}" 'aget '(("name" . "NicK") ("malady" . "on fire")))
help NicK! I'm on fire

upper case variable names results in a full upper case replacement.

(s-format "help ${NAME}! I'm ${malady}" 'aget '(("NAME" . "Nic") ("malady" . "on fire")))
help NICK! I'm on fire

Also case-fold-search has no effect.

Is that an intended feature?

How can I have an upper case variable and a proper case replacement?

Some unexpected results of s-truncate

(s-truncate 2 "Albuquerque") => "Albuquerqu..."
(s-truncate 2 "Ohio") => "Ohi..."
(s-truncate 0 "Ohio") => "O..."
(s-truncate 1 "Ox") => "..."
(s-truncate 0 "Ox") => args-out-of-range

All these results seem unexpected to me.

ucs-normalize takes a bit time to load

#58 fixes a real bug which is very nice, however, the fix requires ucs-normalize unconditionally. This adds 71 ms and doubles Emacs load time at least in my set up.

Is it possible to defer loading of ucs-normalize?
I'm not sure why it takes that long. Maybe it's the ucs-normalize we need to fix. Does anyone has a clue?
Or am I asking too much for too little gain?

Here is an output of benchmark-init-el.

╼►[benchmark-init/root nil 139ms]
  ├─[default load 5ms]
  ├─[avy require 3ms]
  ├─[migemo require 4ms]
  ├─[imenu require 5ms]
  ├─[ring require 4ms]
  ├─[s require 4ms]
  │ ╰─[ucs-normalize require 71ms]
  ├─[popwin require 4ms]
  ├─[dash require 6ms]
  ├─[thingatpt require 4ms]
  ├─[ido-ubiquitous require 9ms]
  │ ╰─[ido-completing-read+ require 3ms]
  ├─[ido-vertical-mode require 2ms]
  │ ╰─[ido require 11ms]
  ╰─[bind-key require 3ms]

Documentation unhelpful for non-experts

s.el is recommended all over the internet, e.g. Stack Overflow, so I installed it. I'm no emacs expert, but I'm also no emacs noob. I've memorized most of the emacs guided tour, have a long (copy-pasted) .emacs file, and use rectangle mode and regexps often. But after reading your readme, I can't figure out how to call your functions from an editor.

My use case is simple. I want to run an s- command on a region (selected with C-SPC) or a buffer. The manual doesn't give instructions or a link to a guide on how to do this. I understand that it's probably a more general emacs subject, but I still think a single sentence and a link could save some people a lot of frustration. People who won't post, but will quietly give up on using your project.

Empty vs. blank

Writing s-presence and s-present? made me think. I think s should change the definition of s-blank?.

I consider the string " " to be blank, but not empty. Right now, it is not blank.

This is the spec I'm proposing:

s-empty?

(s-empty? "") ;; => t
(s-empty? nil) ;; => t
(s-empty? " ") ;; => nil
(s-empty? "    ") ;; => nil
(s-empty? "foo") ;; => nil

s-blank?

(s-blank? "") ;; => t
(s-blank? nil) ;; => t
(s-blank? " ") ;; => t
(s-blank? "    ") ;; => t
(s-blank? "foo") ;; => nil

s-present? (aka. !s-blank?)

(s-present? "") ;; => nil
(s-present? nil) ;; => nil
(s-present? " ") ;; => nil
(s-present? "    ") ;; => nil
(s-present? "foo") ;; => t

(These changes are breaking and I'm not sure if you are planning to release a new major any time soon)

`s-format` and `s-lex-format` fail with “Invalid use of `\' in replacement text” on literal backslash

With dash.el 20130513.1618 from MELPA (should be commit 430e5e3), s-lex-format fails with “Invalid use of `' in replacement text”, if the replacement variable is a string containing a literal backslash:

(let ((foo "Hello\\nWorld")) (s-lex-format "${foo}"))
Debugger entered--Lisp error: (error "Invalid use of `\\' in replacement text")
  replace-match("Hello\\nWorld" nil nil "${foo}" nil)
  replace-regexp-in-string("\\$\\({\\([^}]+\\)}\\|[0-9]+\\)" #[(md) "\306\307�\"\211�\203
    \202�\310\306\311�\"!)\312 ��\313\216\f\314=\203'\f�
\"\202T\f\315=\2034\316
�\"\202T\f\317=\203A\f
�\"\202T\320��!\210
\203Q\f�
\"\202T\f�!\211��\203_��\202c\321\322�\",\207" [md m replacer-match-data var replacer extra match-string 2 string-to-number 1 match-data ((set-match-data replacer-match-data)) gethash aget s--aget elt set-match-data signal s-format-resolve saved-match-data v] 5] "${foo}")
  s-format("${foo}" aget (("foo" . "Hello\\nWorld")))
  (s-lex-format "${foo}")
  (let ((foo "Hello\\nWorld")) (s-lex-format "${foo}"))
  eval((let ((foo "Hello\\nWorld")) (s-lex-format "${foo}")) nil)
  eval-last-sexp-1(t)
  eval-last-sexp(t)
  eval-print-last-sexp()
  call-interactively(eval-print-last-sexp nil nil)
  command-execute(eval-print-last-sexp)

s-format suffers from the same issue:

(s-format "$0" 'elt '("Hello\\nWorld"))
*** Eval error ***  Invalid use of `\' in replacement text

Sorry for not providing more information, but the whole s-format business is somewhat black magic to me, and I couldn't get my head around its code.

confusing version numbers

The version in the s.el file is 1.10.0. That file was updated a month ago. There is a commit message from seven months ago saying that the current version of s is 1.11.0.

Using `case-fold-search`

I'm wondering if your code should not use case-fold-search instead of receiving an ignore-case parameter.

Improve doc for s-truncate

This is pretty low priority, but I suggest changing the doc of s-truncate from

"If S is longer than LEN, cut it down and add ... at the end."

To

"If S is longer than LEN, cut it down to LEN - 3 and add ... at the end."

The original is slightly misleading.

underscores are not treated as word seperators

(s-lower-camel-case "foo_bar") produces "foo_bar".
Expected Output is fooBar

(s-upper-camel-case "foo_bar") produces "foo_Bar".
Expected output is FooBar

I believe the fix is to replace underscores with spaces in the function s-split-words.

Add s-space-words?

Similar to s-dash-words, s-snake-case etc. but returning space separated words.

Implementation could be something like

(s-join " " (s-split-words arg))

Please stop bundling third-party libraries

s is mirrored on the Emacsmirror, which is a large up-to-date collection of Emacs packages.

As the maintainer of the mirror I am trying to resolve feature conflicts that result from one package bundling libraries from another package. I suspect in most cases these libraries were included so that users would not have to find, download and install each dependency manually.

Unfortunately bundling also has negative side-effects: if the bundled libraries are also installed separately, then it is undefined which version actually gets loaded when the respective feature is required.

Initially that isn't a big problem but in many cases upstream changes are not included or only after a long delay. This can be very confusing for users who are not aware that some of the installed packages bundle libraries which are also installed separately. In other cases bugs are fixed in the bundled versions but the fixes are never submitted to upstream.

Also now that Emacs contains the package.el package manager there is a better way to not require users to manually deal with dependencies: add the package (and when that hasn't been done yet the dependencies) to the Melpa package repository. If make is required to install your make you might want to add it to the el-get (another popular package manager) package repository instead.

Alternatively if you want to keep bundling these libraries please move them to a directory only containing bundled libraries and add the file ".nosearch" to that directory. You can then load the library using something like this:

(or (require 'bundled nil t)
    (let ((load-path
           (cons (expand-file-name "fallback-libs"
                                   (or load-file-name buffer-file-name)
                                   load-path))))
      (require 'bundled)))

Of course if your version differs from the upstream version this might not be enough in which case you should make an effort to get your changes merged upstream.

s bundles at least the following libraries:

  • ert

Best regards,
Jonas

s-split-up-to: drops part of string if it ends with separator

If the string contains exactly one more separator than the n argument, and that occurrence is at the end of the string, the last item in the result will be an empty string instead of the rest of the string.

New test cases (the first new one currently fails and returns ("foo" "bar" ""), the second passes):

diff --git a/dev/examples.el b/dev/examples.el
index 44efe97..1d41f43 100644
--- a/dev/examples.el
+++ b/dev/examples.el
@@ -158,7 +158,9 @@
     (s-split-up-to "\n" "z\nefg\n" 5) => '("z" "efg" "")
     (s-split-up-to "\n" "z\nefg\n" 5 t) => '("z" "efg")
     (s-split-up-to "|" "foo||bar|baz|qux" 10) => '("foo" "" "bar" "baz" "qux")
-    (s-split-up-to "|" "foo||bar|baz|qux" 10 t) => '("foo" "bar" "baz" "qux"))
+    (s-split-up-to "|" "foo||bar|baz|qux" 10 t) => '("foo" "bar" "baz" "qux")
+    (s-split-up-to "|" "foo|bar|baz|" 2) => '("foo" "bar" "baz|")
+    (s-split-up-to "|" "foo|bar|baz|qux|" 2) => '("foo" "bar" "baz|qux|"))

   (defexamples s-join
     (s-join "+" '("abc" "def" "ghi")) => "abc+def+ghi"

Find all occurences by regex

Python has re.findall:

>>> s = "apple orange lemon"
>>> r = "[a-z]+"
>>> re.findall(r, s)
['apple', 'orange', 'lemon']

How do i accomplish the same with s.el? s-match and s-match-strings-all don't work this way:

ELISP> (s-match "[a-z]+" "apple orange lemon")
("apple")
ELISP> (s-match-strings-all "[a-z]+" "apple orange lemon")
(("apple")
 ("pple")
 ("ple")
 ("le")
 ("e")
 ("orange")
 ("range")
 ("ange")
 ("nge")
 ("ge")
 ("e")
 ("lemon")
 ("emon")
 ("mon")
 ("on")
 ("n"))

Currently i use s-match repeatedly, by applying it to a string that is shortened each time by the length of the match.

enhancement: `s-extract-match` to get a (sub)match from a string

I find myself, more often than I would like, performing single element extraction based on a regex; the implementation is probably trivially obvious, but proposed signature:

(s-extract-match regexp s &optional subexp-depth)

Returns the Nth subexpression match, defaulting to "0" or full match, from running regexp vs string.

Feature request: add an analogy of `strstr`

A function which given a string and a pattern should return the first index where the pattern matches or nil on failure.

Avoids useless wrapping in save-matck-data and calls to inspect the state...

api could be like

(s-match-position string regexp)
(s-match-position-all string regexp)

A good entry-level patch, for people interested in trying emacs lisp.

s-snake-case and s-upper-camel-case can't be composed

I was writing a command to cycle between different capitalisation formats, but noticed that I can't always use s-snake-case to invert s-upper-camel-case.

(s-snake-case (s-upper-camel-case "f_foo_bar")) ;; "ffoo_bar"

The same is true of s-dashed-words:

(s-dashed-words (s-upper-camel-case "f-foo-bar")) ;; "ffoo-bar"

It's not catastrophic, but if s.el fixed this then I can throw away a number of functions I've written myself.

s-lex-format does not accept variable

I really like the idea discussed in #27 of using lexical formatting with s-format but I ran into a wrong-type-argument sequencep with the following:

(let ((string "x is ${x}")
      (x "foo"))
  (s-lex-format string))

To my mind that should work, but, I can just as easily get results with the following:

(let ((string "x is ${x}")
      (x "foo"))
  (s-format string
            '(lambda (var)
               (symbol-value (intern var)))))
=>
"x is foo"

I am probably missing something because I really have next to no idea what I'm doing, but my question is: should s-lex-format accept a variable as argument, or, more basically, why not include a 'lex replacer in s-format?

s-split with limit

It would be nice to have a way to split a string on a character/regexp but only take first n strings and the rest as unsplitted. Most of the apis elsewhere have this functionality and it's lacking. For example, splitting songs or anything like so "Author - Some-song" could be easily done with limit 2 and split on "-". I think the use-case is clear.

The issue here is only this: should it be an optional argument or do we need a new function? It's a shame there's the omit-nulls argument as third one, because this would be probably more useful option to have it listed first.

s-lower-camel-case & s-upper-camel-case not replacing underscores

When I use either of the above functions (s-dashed-words as well), I get the same input back.

Ex:

(s-lower-camel-case "under_scored_words")
"under_scored_words"

Do you happen to know of any conflicts with the below modes, or what I should check in my emacs configuration that could be messing with these functions? Thanks so much!

Modes

Major mode: Go

Enabled minor modes: Auto-Complete Auto-Composition Auto-Compression
Auto-Encryption Blink-Cursor Column-Number Delete-Selection
Electric-Indent Electric-Pair Erc-Autojoin Erc-Button Erc-Fill
Erc-Irccontrols Erc-List Erc-Match Erc-Menu Erc-Move-To-Prompt
Erc-Netsplit Erc-Networks Erc-Noncommands Erc-Pcomplete Erc-Readonly
Erc-Ring Erc-Stamp Erc-Track Erc-Track File-Name-Shadow Flycheck
Font-Lock Global-Auto-Complete Global-Auto-Revert Global-Flycheck
Global-Font-Lock Global-Hl-Line Ido-Everywhere Jabber-Activity
Line-Number Linum Menu-Bar Mouse-Wheel Recentf Savehist Shell-Dirtrack
Show-Paren Superword Tooltip Transient-Mark Winner Yas

Document that s-lex-format is a macro

I also don't quite get why it is a macro. this function used with s-format is what I expected:

(defun s-format-helper (var-name)
(let ((symbol (intern var-name)))
(if (boundp symbol)
(symbol-value symbol)
(error "symbol %s has no value" var-name))))

`string-prefix-p` is not defined in Emacs 23.1

I noticed that string-prefix-p is not defined in Emacs 23.1. It is defined in Emacs 23.3. I don't know if it is defined in 23.2.

Here is a backward compatible implementation:

(defun request-testing-string-prefix-p (prefix str &optional ignore-case)
  (let ((case-fold-search ignore-case))
    (string-match-p (format "^%s" (regexp-quote prefix)) str)))

-- https://github.com/tkf/emacs-request/blob/master/tests/request-testing.el#L36

Probably you can do the same in s.el?

Functions not visibile despite "require" mention

Dear Magnar,
Many thanks for the wonderful packages that you provide.
I came across "s.el" that I downloaded via elap. I find it contains many interesting functions. Despite the mention (require 's), the functions are not visibile from within emacs buffers.

However, as example, M-x describe-function RET s-collapse-whitespace works well

Is there a way to make these functions applicable on marked text in emacs buffers ?

Here are the two lines relative to s.el in my .emacs
(add-to-list 'load-path "~/.emacs.d/elpa/s-20140714.707")
(require 's)

Many thanks in advance ...
P.K

run-tests.sh reports unrelated test failures as fails.

If I run the tests, they all pass.

But if I take the first one, and modify it to be this:

  (defexamples s-trim
    (s-trim "trim ") => "trim     more space so this test fails"

I get 7 test failures, of seemingly unrelated tests:

Ran 67 tests, 60 results as expected, 7 unexpected (2018-02-25 02:37:40-0500)

7 unexpected results:
   FAILED  s-trim
   FAILED  s-trim-left
   FAILED  s-trim-right
   FAILED  s-upper-camel-case
   FAILED  s-with
   FAILED  s-word-initials
   FAILED  s-word-wrap

I've pasted the log for one of the failing tests that I don't think should fail. I can't really read why it failed.

Test s-word-wrap backtrace:
  (let* ((condition (first more-debugger-args)) (type (let* ((temp (ca
  (cond ((memql first-debugger-arg (quote (lambda debug t exit nil))) 
  (let* ((more-debugger-args debugger-args) (first-debugger-arg (if mo
  ert--run-test-debugger(#s(ert--test-execution-info #s(ert-test s-wor
  (lambda (G1 &rest debugger-args) (ert--run-test-debugger (symbol-val
  apply((lambda (G1 &rest debugger-args) (ert--run-test-debugger (symb
  (lambda (&rest --cl-rest--) (apply (function (lambda (G1 &rest debug
  signal(ert-test-failed (((should (equal (match-data) previous-match-
  ert-fail(((should (equal (match-data) previous-match-data)) :form (e
  (if (unwind-protect (setq value-127 (apply fn-125 args-126)) (setq f
  (let (form-description-129) (if (unwind-protect (setq value-127 (app
  (let ((value-127 (quote ert-form-evaluation-aborted-128))) (let (for
  (let ((fn-125 (function equal)) (args-126 (list (match-data) previou
  (let ((previous-match-data (match-data))) (let ((fn-120 (function eq
  (closure (t) nil (let ((previous-match-data (match-data))) (let ((fn
  funcall((closure (t) nil (let ((previous-match-data (match-data))) (
  (let ((debugger (list (quote lambda) (quote (&rest --cl-rest--)) (li
  (progn (let ((debugger (list (quote lambda) (quote (&rest --cl-rest-
  (unwind-protect (progn (let ((debugger (list (quote lambda) (quote (
  (let ((wconfig (current-window-configuration))) (unwind-protect (pro
  (progn (let ((wconfig (current-window-configuration))) (unwind-prote
  (unwind-protect (progn (let ((wconfig (current-window-configuration)
  (save-current-buffer (set-buffer temp-buffer) (unwind-protect (progn
  (let ((temp-buffer (generate-new-buffer " *temp*"))) (save-current-b
  (catch (quote ert--pass) (let ((temp-buffer (generate-new-buffer " *
  (progn (progn (progn "Access slot \"next-debugger\" of `ert--test-ex
  (let ((--cl-info-- (make-symbol "--info--"))) (let* ((v --cl-info--)
  ert--run-test-internal(#s(ert--test-execution-info #s(ert-test s-wor
  (let ((ert--should-execution-observer (list (quote lambda) (quote (&
  (unwind-protect (let ((ert--should-execution-observer (list (quote l
  (let ((--cl-info-- (make-symbol "--info--")) (--cl-should-form-accu-
  (unwind-protect (let ((--cl-info-- (make-symbol "--info--")) (--cl-s
  (let ((--cl-begin-marker-- (make-symbol "--begin-marker--"))) (let* 
  (catch (quote --cl-block-error--) (let ((--cl-begin-marker-- (make-s
  ert-run-test(#s(ert-test s-word-wrap nil (closure (t) nil (let ((pre
  (unwind-protect (ert-run-test test) (let* ((v (progn "Access slot \"
  (let ((ert--current-run-stats stats) (pos (ert--stats-test-pos stats
  ert-run-or-rerun-test(#s(ert--stats t [#s(ert-test s-append nil (clo
  (while (consp --cl-var--) (setq test (car --cl-var--)) (ert-run-or-r
  (let* ((--cl-var-- tests) (test nil)) (while (consp --cl-var--) (set
  (progn (let* ((--cl-var-- tests) (test nil)) (while (consp --cl-var-
  (unwind-protect (progn (let* ((--cl-var-- tests) (test nil)) (while 
  (let ((ert--current-run-stats stats)) (force-mode-line-update) (unwi
  (unwind-protect (let ((ert--current-run-stats stats)) (force-mode-li
  (let ((abortedp t)) (unwind-protect (let ((ert--current-run-stats st
  (let* ((tests (ert-select-tests selector t)) (stats (ert--make-stats
  ert-run-tests(t (lambda (event-type &rest event-args) (cond ((eql ev
  ert-run-tests-batch(nil)
  (let ((stats (ert-run-tests-batch selector))) (kill-emacs (if (= 0 (
  (unwind-protect (let ((stats (ert-run-tests-batch selector))) (kill-
  ert-run-tests-batch-and-exit()
  command-line-1(("-l" "dev/ert.el" "-l" "dev/examples-to-tests.el" "-
  command-line()
  normal-top-level()
Test s-word-wrap condition:
    (ert-test-failed
     ((should
       (equal
	(match-data)
	previous-match-data))
      :form
      (equal
       (0 0)
       (#<marker in no buffer> #<marker in no buffer>))
      :value nil :explanation
      (list-elt 0
		(different-types 0 #<marker in no buffer>))))
   FAILED  66/67  s-word-wrap

s-join variant with beginning and end

scala's mkString function takes three parameters: begin sep end which means a list can be converted into [foo,bar] very easily. Such a function would be a great addition to this library!

s-count-matches doesn't count overlapping matches

ELISP> (s-count-matches "HH" "HHH")
1 (#o1, #x1, ?\C-a)

This returns 1. I think it should be 2.

There's seemingly a mismatch with s-match-strings-all. I would expect (length (s-match-strings-all some-regex some-list)) to return the same thing as (s-count-matches some-regex some-list). But it doesn't:

ELISP> (s-match-strings-all "HH" "HHH")
(("HH")
 ("HH"))

I suspect this is because s-count-matches delegates to the built-in count-matches, which doesn't count overlapping regex matches. But, at least to me, this is unintuitive behavior that isn't obvious from the documentation. Is there a function which returns the same as (length (s-match-strings-all some-regex some-list))? I can't find one.

optional argument omit-nulls for s-lines ?

On GNU/Linux text files usually have trailing newlines. This newlines prove to be a nuisance every time all I want is to just break the contents of a file into lines. I instead use (s-split "[\n\r]" some-text t) and have this regex for compatibility over OSes. Maybe s-lines should have an optional omit-nulls argument? Or should f.el's f-read-text have an optional omit-trailing-newline argument instead?

EDIT: Ok, there's s-chomp for removing trailing newlines, keep forgetting that.

Provide foo-p aliases of foo? commands

Many s.el functions have -p aliases, but not all. For example, s-capitalized? does not. It would be nice to have aliases for all predicate functions.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.