Klimi's new dotfiles with stow.
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

747 lines
24 KiB

  1. ;;; s.el --- The long lost Emacs string manipulation library.
  2. ;; Copyright (C) 2012-2015 Magnar Sveen
  3. ;; Author: Magnar Sveen <magnars@gmail.com>
  4. ;; Version: 1.12.0
  5. ;; Package-Version: 20180406.808
  6. ;; Keywords: strings
  7. ;; This program is free software; you can redistribute it and/or modify
  8. ;; it under the terms of the GNU General Public License as published by
  9. ;; the Free Software Foundation, either version 3 of the License, or
  10. ;; (at your option) any later version.
  11. ;; This program is distributed in the hope that it will be useful,
  12. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. ;; GNU General Public License for more details.
  15. ;; You should have received a copy of the GNU General Public License
  16. ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. ;;; Commentary:
  18. ;; The long lost Emacs string manipulation library.
  19. ;;
  20. ;; See documentation on https://github.com/magnars/s.el#functions
  21. ;;; Code:
  22. ;; Silence byte-compiler
  23. (defvar ucs-normalize-combining-chars) ; Defined in `ucs-normalize'
  24. (autoload 'slot-value "eieio")
  25. (defun s-trim-left (s)
  26. "Remove whitespace at the beginning of S."
  27. (declare (pure t) (side-effect-free t))
  28. (save-match-data
  29. (if (string-match "\\`[ \t\n\r]+" s)
  30. (replace-match "" t t s)
  31. s)))
  32. (defun s-trim-right (s)
  33. "Remove whitespace at the end of S."
  34. (save-match-data
  35. (declare (pure t) (side-effect-free t))
  36. (if (string-match "[ \t\n\r]+\\'" s)
  37. (replace-match "" t t s)
  38. s)))
  39. (defun s-trim (s)
  40. "Remove whitespace at the beginning and end of S."
  41. (declare (pure t) (side-effect-free t))
  42. (s-trim-left (s-trim-right s)))
  43. (defun s-collapse-whitespace (s)
  44. "Convert all adjacent whitespace characters to a single space."
  45. (declare (pure t) (side-effect-free t))
  46. (replace-regexp-in-string "[ \t\n\r]+" " " s))
  47. (defun s-split (separator s &optional omit-nulls)
  48. "Split S into substrings bounded by matches for regexp SEPARATOR.
  49. If OMIT-NULLS is non-nil, zero-length substrings are omitted.
  50. This is a simple wrapper around the built-in `split-string'."
  51. (declare (side-effect-free t))
  52. (save-match-data
  53. (split-string s separator omit-nulls)))
  54. (defun s-split-up-to (separator s n &optional omit-nulls)
  55. "Split S up to N times into substrings bounded by matches for regexp SEPARATOR.
  56. If OMIT-NULLS is non-nil, zero-length substrings are omitted.
  57. See also `s-split'."
  58. (declare (side-effect-free t))
  59. (save-match-data
  60. (let ((op 0)
  61. (r nil))
  62. (with-temp-buffer
  63. (insert s)
  64. (setq op (goto-char (point-min)))
  65. (while (and (re-search-forward separator nil t)
  66. (< 0 n))
  67. (let ((sub (buffer-substring op (match-beginning 0))))
  68. (unless (and omit-nulls
  69. (equal sub ""))
  70. (push sub r)))
  71. (setq op (goto-char (match-end 0)))
  72. (setq n (1- n)))
  73. (let ((sub (buffer-substring op (point-max))))
  74. (unless (and omit-nulls
  75. (equal sub ""))
  76. (push sub r))))
  77. (nreverse r))))
  78. (defun s-lines (s)
  79. "Splits S into a list of strings on newline characters."
  80. (declare (pure t) (side-effect-free t))
  81. (s-split "\\(\r\n\\|[\n\r]\\)" s))
  82. (defun s-join (separator strings)
  83. "Join all the strings in STRINGS with SEPARATOR in between."
  84. (declare (pure t) (side-effect-free t))
  85. (mapconcat 'identity strings separator))
  86. (defun s-concat (&rest strings)
  87. "Join all the string arguments into one string."
  88. (declare (pure t) (side-effect-free t))
  89. (apply 'concat strings))
  90. (defun s-prepend (prefix s)
  91. "Concatenate PREFIX and S."
  92. (declare (pure t) (side-effect-free t))
  93. (concat prefix s))
  94. (defun s-append (suffix s)
  95. "Concatenate S and SUFFIX."
  96. (declare (pure t) (side-effect-free t))
  97. (concat s suffix))
  98. (defun s-repeat (num s)
  99. "Make a string of S repeated NUM times."
  100. (declare (pure t) (side-effect-free t))
  101. (let (ss)
  102. (while (> num 0)
  103. (setq ss (cons s ss))
  104. (setq num (1- num)))
  105. (apply 'concat ss)))
  106. (defun s-chop-suffix (suffix s)
  107. "Remove SUFFIX if it is at end of S."
  108. (declare (pure t) (side-effect-free t))
  109. (let ((pos (- (length suffix))))
  110. (if (and (>= (length s) (length suffix))
  111. (string= suffix (substring s pos)))
  112. (substring s 0 pos)
  113. s)))
  114. (defun s-chop-suffixes (suffixes s)
  115. "Remove SUFFIXES one by one in order, if they are at the end of S."
  116. (declare (pure t) (side-effect-free t))
  117. (while suffixes
  118. (setq s (s-chop-suffix (car suffixes) s))
  119. (setq suffixes (cdr suffixes)))
  120. s)
  121. (defun s-chop-prefix (prefix s)
  122. "Remove PREFIX if it is at the start of S."
  123. (declare (pure t) (side-effect-free t))
  124. (let ((pos (length prefix)))
  125. (if (and (>= (length s) (length prefix))
  126. (string= prefix (substring s 0 pos)))
  127. (substring s pos)
  128. s)))
  129. (defun s-chop-prefixes (prefixes s)
  130. "Remove PREFIXES one by one in order, if they are at the start of S."
  131. (declare (pure t) (side-effect-free t))
  132. (while prefixes
  133. (setq s (s-chop-prefix (car prefixes) s))
  134. (setq prefixes (cdr prefixes)))
  135. s)
  136. (defun s-shared-start (s1 s2)
  137. "Returns the longest prefix S1 and S2 have in common."
  138. (declare (pure t) (side-effect-free t))
  139. (let ((search-length (min (length s1) (length s2)))
  140. (i 0))
  141. (while (and (< i search-length)
  142. (= (aref s1 i) (aref s2 i)))
  143. (setq i (1+ i)))
  144. (substring s1 0 i)))
  145. (defun s-shared-end (s1 s2)
  146. "Returns the longest suffix S1 and S2 have in common."
  147. (declare (pure t) (side-effect-free t))
  148. (let* ((l1 (length s1))
  149. (l2 (length s2))
  150. (search-length (min l1 l2))
  151. (i 0))
  152. (while (and (< i search-length)
  153. (= (aref s1 (- l1 i 1)) (aref s2 (- l2 i 1))))
  154. (setq i (1+ i)))
  155. ;; If I is 0, then it means that there's no common suffix between
  156. ;; S1 and S2.
  157. ;;
  158. ;; However, since (substring s (- 0)) will return the whole
  159. ;; string, `s-shared-end' should simply return the empty string
  160. ;; when I is 0.
  161. (if (zerop i)
  162. ""
  163. (substring s1 (- i)))))
  164. (defun s-chomp (s)
  165. "Remove one trailing `\\n`, `\\r` or `\\r\\n` from S."
  166. (declare (pure t) (side-effect-free t))
  167. (s-chop-suffixes '("\n" "\r") s))
  168. (defun s-truncate (len s &optional ellipsis)
  169. "If S is longer than LEN, cut it down and add ELLIPSIS to the end.
  170. The resulting string, including ellipsis, will be LEN characters
  171. long.
  172. When not specified, ELLIPSIS defaults to ...."
  173. (declare (pure t) (side-effect-free t))
  174. (unless ellipsis
  175. (setq ellipsis "..."))
  176. (if (> (length s) len)
  177. (format "%s%s" (substring s 0 (- len (length ellipsis))) ellipsis)
  178. s))
  179. (defun s-word-wrap (len s)
  180. "If S is longer than LEN, wrap the words with newlines."
  181. (declare (side-effect-free t))
  182. (save-match-data
  183. (with-temp-buffer
  184. (insert s)
  185. (let ((fill-column len))
  186. (fill-region (point-min) (point-max)))
  187. (buffer-substring (point-min) (point-max)))))
  188. (defun s-center (len s)
  189. "If S is shorter than LEN, pad it with spaces so it is centered."
  190. (declare (pure t) (side-effect-free t))
  191. (let ((extra (max 0 (- len (length s)))))
  192. (concat
  193. (make-string (ceiling extra 2) ? )
  194. s
  195. (make-string (floor extra 2) ? ))))
  196. (defun s-pad-left (len padding s)
  197. "If S is shorter than LEN, pad it with PADDING on the left."
  198. (declare (pure t) (side-effect-free t))
  199. (let ((extra (max 0 (- len (length s)))))
  200. (concat (make-string extra (string-to-char padding))
  201. s)))
  202. (defun s-pad-right (len padding s)
  203. "If S is shorter than LEN, pad it with PADDING on the right."
  204. (declare (pure t) (side-effect-free t))
  205. (let ((extra (max 0 (- len (length s)))))
  206. (concat s
  207. (make-string extra (string-to-char padding)))))
  208. (defun s-left (len s)
  209. "Returns up to the LEN first chars of S."
  210. (declare (pure t) (side-effect-free t))
  211. (if (> (length s) len)
  212. (substring s 0 len)
  213. s))
  214. (defun s-right (len s)
  215. "Returns up to the LEN last chars of S."
  216. (declare (pure t) (side-effect-free t))
  217. (let ((l (length s)))
  218. (if (> l len)
  219. (substring s (- l len) l)
  220. s)))
  221. (defun s-ends-with? (suffix s &optional ignore-case)
  222. "Does S end with SUFFIX?
  223. If IGNORE-CASE is non-nil, the comparison is done without paying
  224. attention to case differences.
  225. Alias: `s-suffix?'"
  226. (declare (pure t) (side-effect-free t))
  227. (let ((start-pos (- (length s) (length suffix))))
  228. (and (>= start-pos 0)
  229. (eq t (compare-strings suffix nil nil
  230. s start-pos nil ignore-case)))))
  231. (defun s-starts-with? (prefix s &optional ignore-case)
  232. "Does S start with PREFIX?
  233. If IGNORE-CASE is non-nil, the comparison is done without paying
  234. attention to case differences.
  235. Alias: `s-prefix?'. This is a simple wrapper around the built-in
  236. `string-prefix-p'."
  237. (declare (pure t) (side-effect-free t))
  238. (string-prefix-p prefix s ignore-case))
  239. (defun s--truthy? (val)
  240. (declare (pure t) (side-effect-free t))
  241. (not (null val)))
  242. (defun s-contains? (needle s &optional ignore-case)
  243. "Does S contain NEEDLE?
  244. If IGNORE-CASE is non-nil, the comparison is done without paying
  245. attention to case differences."
  246. (declare (pure t) (side-effect-free t))
  247. (let ((case-fold-search ignore-case))
  248. (s--truthy? (string-match-p (regexp-quote needle) s))))
  249. (defun s-equals? (s1 s2)
  250. "Is S1 equal to S2?
  251. This is a simple wrapper around the built-in `string-equal'."
  252. (declare (pure t) (side-effect-free t))
  253. (string-equal s1 s2))
  254. (defun s-less? (s1 s2)
  255. "Is S1 less than S2?
  256. This is a simple wrapper around the built-in `string-lessp'."
  257. (declare (pure t) (side-effect-free t))
  258. (string-lessp s1 s2))
  259. (defun s-matches? (regexp s &optional start)
  260. "Does REGEXP match S?
  261. If START is non-nil the search starts at that index.
  262. This is a simple wrapper around the built-in `string-match-p'."
  263. (declare (side-effect-free t))
  264. (s--truthy? (string-match-p regexp s start)))
  265. (defun s-blank? (s)
  266. "Is S nil or the empty string?"
  267. (declare (pure t) (side-effect-free t))
  268. (or (null s) (string= "" s)))
  269. (defun s-blank-str? (s)
  270. "Is S nil or the empty string or string only contains whitespace?"
  271. (declare (pure t) (side-effect-free t))
  272. (or (s-blank? s) (s-blank? (s-trim s))))
  273. (defun s-present? (s)
  274. "Is S anything but nil or the empty string?"
  275. (declare (pure t) (side-effect-free t))
  276. (not (s-blank? s)))
  277. (defun s-presence (s)
  278. "Return S if it's `s-present?', otherwise return nil."
  279. (declare (pure t) (side-effect-free t))
  280. (and (s-present? s) s))
  281. (defun s-lowercase? (s)
  282. "Are all the letters in S in lower case?"
  283. (declare (side-effect-free t))
  284. (let ((case-fold-search nil))
  285. (not (string-match-p "[[:upper:]]" s))))
  286. (defun s-uppercase? (s)
  287. "Are all the letters in S in upper case?"
  288. (declare (side-effect-free t))
  289. (let ((case-fold-search nil))
  290. (not (string-match-p "[[:lower:]]" s))))
  291. (defun s-mixedcase? (s)
  292. "Are there both lower case and upper case letters in S?"
  293. (let ((case-fold-search nil))
  294. (s--truthy?
  295. (and (string-match-p "[[:lower:]]" s)
  296. (string-match-p "[[:upper:]]" s)))))
  297. (defun s-capitalized? (s)
  298. "In S, is the first letter upper case, and all other letters lower case?"
  299. (declare (side-effect-free t))
  300. (let ((case-fold-search nil))
  301. (s--truthy?
  302. (string-match-p "^[[:upper:]][^[:upper:]]*$" s))))
  303. (defun s-numeric? (s)
  304. "Is S a number?"
  305. (declare (pure t) (side-effect-free t))
  306. (s--truthy?
  307. (string-match-p "^[0-9]+$" s)))
  308. (defun s-replace (old new s)
  309. "Replaces OLD with NEW in S."
  310. (declare (pure t) (side-effect-free t))
  311. (replace-regexp-in-string (regexp-quote old) new s t t))
  312. (defalias 's-replace-regexp 'replace-regexp-in-string)
  313. (defun s--aget (alist key)
  314. (declare (pure t) (side-effect-free t))
  315. (cdr (assoc-string key alist)))
  316. (defun s-replace-all (replacements s)
  317. "REPLACEMENTS is a list of cons-cells. Each `car` is replaced with `cdr` in S."
  318. (declare (pure t) (side-effect-free t))
  319. (replace-regexp-in-string (regexp-opt (mapcar 'car replacements))
  320. (lambda (it) (s--aget replacements it))
  321. s t t))
  322. (defun s-downcase (s)
  323. "Convert S to lower case.
  324. This is a simple wrapper around the built-in `downcase'."
  325. (declare (side-effect-free t))
  326. (downcase s))
  327. (defun s-upcase (s)
  328. "Convert S to upper case.
  329. This is a simple wrapper around the built-in `upcase'."
  330. (declare (side-effect-free t))
  331. (upcase s))
  332. (defun s-capitalize (s)
  333. "Convert the first word's first character to upper case and the rest to lower case in S."
  334. (declare (side-effect-free t))
  335. (concat (upcase (substring s 0 1)) (downcase (substring s 1))))
  336. (defun s-titleize (s)
  337. "Convert each word's first character to upper case and the rest to lower case in S.
  338. This is a simple wrapper around the built-in `capitalize'."
  339. (declare (side-effect-free t))
  340. (capitalize s))
  341. (defmacro s-with (s form &rest more)
  342. "Threads S through the forms. Inserts S as the last item
  343. in the first form, making a list of it if it is not a list
  344. already. If there are more forms, inserts the first form as the
  345. last item in second form, etc."
  346. (declare (debug (form &rest [&or (function &rest form) fboundp])))
  347. (if (null more)
  348. (if (listp form)
  349. `(,(car form) ,@(cdr form) ,s)
  350. (list form s))
  351. `(s-with (s-with ,s ,form) ,@more)))
  352. (put 's-with 'lisp-indent-function 1)
  353. (defun s-index-of (needle s &optional ignore-case)
  354. "Returns first index of NEEDLE in S, or nil.
  355. If IGNORE-CASE is non-nil, the comparison is done without paying
  356. attention to case differences."
  357. (declare (pure t) (side-effect-free t))
  358. (let ((case-fold-search ignore-case))
  359. (string-match-p (regexp-quote needle) s)))
  360. (defun s-reverse (s)
  361. "Return the reverse of S."
  362. (declare (pure t) (side-effect-free t))
  363. (save-match-data
  364. (if (multibyte-string-p s)
  365. (let ((input (string-to-list s))
  366. output)
  367. (require 'ucs-normalize)
  368. (while input
  369. ;; Handle entire grapheme cluster as a single unit
  370. (let ((grapheme (list (pop input))))
  371. (while (memql (car input) ucs-normalize-combining-chars)
  372. (push (pop input) grapheme))
  373. (setq output (nconc (nreverse grapheme) output))))
  374. (concat output))
  375. (concat (nreverse (string-to-list s))))))
  376. (defun s-match-strings-all (regex string)
  377. "Return a list of matches for REGEX in STRING.
  378. Each element itself is a list of matches, as per
  379. `match-string'. Multiple matches at the same position will be
  380. ignored after the first."
  381. (declare (side-effect-free t))
  382. (save-match-data
  383. (let ((all-strings ())
  384. (i 0))
  385. (while (and (< i (length string))
  386. (string-match regex string i))
  387. (setq i (1+ (match-beginning 0)))
  388. (let (strings
  389. (num-matches (/ (length (match-data)) 2))
  390. (match 0))
  391. (while (/= match num-matches)
  392. (push (match-string match string) strings)
  393. (setq match (1+ match)))
  394. (push (nreverse strings) all-strings)))
  395. (nreverse all-strings))))
  396. (defun s-matched-positions-all (regexp string &optional subexp-depth)
  397. "Return a list of matched positions for REGEXP in STRING.
  398. SUBEXP-DEPTH is 0 by default."
  399. (declare (side-effect-free t))
  400. (if (null subexp-depth)
  401. (setq subexp-depth 0))
  402. (save-match-data
  403. (let ((pos 0) result)
  404. (while (and (string-match regexp string pos)
  405. (< pos (length string)))
  406. (let ((m (match-end subexp-depth)))
  407. (push (cons (match-beginning subexp-depth) (match-end subexp-depth)) result)
  408. (setq pos (match-end 0))))
  409. (nreverse result))))
  410. (defun s-match (regexp s &optional start)
  411. "When the given expression matches the string, this function returns a list
  412. of the whole matching string and a string for each matched subexpressions.
  413. If it did not match the returned value is an empty list (nil).
  414. When START is non-nil the search will start at that index."
  415. (declare (side-effect-free t))
  416. (save-match-data
  417. (if (string-match regexp s start)
  418. (let ((match-data-list (match-data))
  419. result)
  420. (while match-data-list
  421. (let* ((beg (car match-data-list))
  422. (end (cadr match-data-list))
  423. (subs (if (and beg end) (substring s beg end) nil)))
  424. (setq result (cons subs result))
  425. (setq match-data-list
  426. (cddr match-data-list))))
  427. (nreverse result)))))
  428. (defun s-slice-at (regexp s)
  429. "Slices S up at every index matching REGEXP."
  430. (declare (side-effect-free t))
  431. (if (= 0 (length s)) (list "")
  432. (save-match-data
  433. (let (i)
  434. (setq i (string-match regexp s 1))
  435. (if i
  436. (cons (substring s 0 i)
  437. (s-slice-at regexp (substring s i)))
  438. (list s))))))
  439. (defun s-split-words (s)
  440. "Split S into list of words."
  441. (declare (side-effect-free t))
  442. (s-split
  443. "[^[:word:]0-9]+"
  444. (let ((case-fold-search nil))
  445. (replace-regexp-in-string
  446. "\\([[:lower:]]\\)\\([[:upper:]]\\)" "\\1 \\2"
  447. (replace-regexp-in-string "\\([[:upper:]]\\)\\([[:upper:]][0-9[:lower:]]\\)" "\\1 \\2" s)))
  448. t))
  449. (defun s--mapcar-head (fn-head fn-rest list)
  450. "Like MAPCAR, but applies a different function to the first element."
  451. (if list
  452. (cons (funcall fn-head (car list)) (mapcar fn-rest (cdr list)))))
  453. (defun s-lower-camel-case (s)
  454. "Convert S to lowerCamelCase."
  455. (declare (side-effect-free t))
  456. (s-join "" (s--mapcar-head 'downcase 'capitalize (s-split-words s))))
  457. (defun s-upper-camel-case (s)
  458. "Convert S to UpperCamelCase."
  459. (declare (side-effect-free t))
  460. (s-join "" (mapcar 'capitalize (s-split-words s))))
  461. (defun s-snake-case (s)
  462. "Convert S to snake_case."
  463. (declare (side-effect-free t))
  464. (s-join "_" (mapcar 'downcase (s-split-words s))))
  465. (defun s-dashed-words (s)
  466. "Convert S to dashed-words."
  467. (declare (side-effect-free t))
  468. (s-join "-" (mapcar 'downcase (s-split-words s))))
  469. (defun s-capitalized-words (s)
  470. "Convert S to Capitalized words."
  471. (declare (side-effect-free t))
  472. (let ((words (s-split-words s)))
  473. (s-join " " (cons (capitalize (car words)) (mapcar 'downcase (cdr words))))))
  474. (defun s-titleized-words (s)
  475. "Convert S to Titleized Words."
  476. (declare (side-effect-free t))
  477. (s-join " " (mapcar 's-titleize (s-split-words s))))
  478. (defun s-word-initials (s)
  479. "Convert S to its initials."
  480. (declare (side-effect-free t))
  481. (s-join "" (mapcar (lambda (ss) (substring ss 0 1))
  482. (s-split-words s))))
  483. ;; Errors for s-format
  484. (progn
  485. (put 's-format-resolve
  486. 'error-conditions
  487. '(error s-format s-format-resolve))
  488. (put 's-format-resolve
  489. 'error-message
  490. "Cannot resolve a template to values"))
  491. (defun s-format (template replacer &optional extra)
  492. "Format TEMPLATE with the function REPLACER.
  493. REPLACER takes an argument of the format variable and optionally
  494. an extra argument which is the EXTRA value from the call to
  495. `s-format'.
  496. Several standard `s-format' helper functions are recognized and
  497. adapted for this:
  498. (s-format \"${name}\" 'gethash hash-table)
  499. (s-format \"${name}\" 'aget alist)
  500. (s-format \"$0\" 'elt sequence)
  501. The REPLACER function may be used to do any other kind of
  502. transformation."
  503. (let ((saved-match-data (match-data)))
  504. (unwind-protect
  505. (replace-regexp-in-string
  506. "\\$\\({\\([^}]+\\)}\\|[0-9]+\\)"
  507. (lambda (md)
  508. (let ((var
  509. (let ((m (match-string 2 md)))
  510. (if m m
  511. (string-to-number (match-string 1 md)))))
  512. (replacer-match-data (match-data)))
  513. (unwind-protect
  514. (let ((v
  515. (cond
  516. ((eq replacer 'gethash)
  517. (funcall replacer var extra))
  518. ((eq replacer 'aget)
  519. (funcall 's--aget extra var))
  520. ((eq replacer 'elt)
  521. (funcall replacer extra var))
  522. ((eq replacer 'oref)
  523. (funcall #'slot-value extra (intern var)))
  524. (t
  525. (set-match-data saved-match-data)
  526. (if extra
  527. (funcall replacer var extra)
  528. (funcall replacer var))))))
  529. (if v (format "%s" v) (signal 's-format-resolve md)))
  530. (set-match-data replacer-match-data)))) template
  531. ;; Need literal to make sure it works
  532. t t)
  533. (set-match-data saved-match-data))))
  534. (defvar s-lex-value-as-lisp nil
  535. "If `t' interpolate lisp values as lisp.
  536. `s-lex-format' inserts values with (format \"%S\").")
  537. (defun s-lex-fmt|expand (fmt)
  538. "Expand FMT into lisp."
  539. (declare (side-effect-free t))
  540. (list 's-format fmt (quote 'aget)
  541. (append '(list)
  542. (mapcar
  543. (lambda (matches)
  544. (list
  545. 'cons
  546. (cadr matches)
  547. `(format
  548. (if s-lex-value-as-lisp "%S" "%s")
  549. ,(intern (cadr matches)))))
  550. (s-match-strings-all "${\\([^}]+\\)}" fmt)))))
  551. (defmacro s-lex-format (format-str)
  552. "`s-format` with the current environment.
  553. FORMAT-STR may use the `s-format' variable reference to refer to
  554. any variable:
  555. (let ((x 1))
  556. (s-lex-format \"x is: ${x}\"))
  557. The values of the variables are interpolated with \"%s\" unless
  558. the variable `s-lex-value-as-lisp' is `t' and then they are
  559. interpolated with \"%S\"."
  560. (declare (debug (form)))
  561. (s-lex-fmt|expand format-str))
  562. (defun s-count-matches (regexp s &optional start end)
  563. "Count occurrences of `regexp' in `s'.
  564. `start', inclusive, and `end', exclusive, delimit the part of `s' to
  565. match. `start' and `end' are both indexed starting at 1; the initial
  566. character in `s' is index 1.
  567. This function starts looking for the next match from the end of the
  568. previous match. Hence, it ignores matches that overlap a previously
  569. found match. To count overlapping matches, use
  570. `s-count-matches-all'."
  571. (declare (side-effect-free t))
  572. (save-match-data
  573. (with-temp-buffer
  574. (insert s)
  575. (goto-char (point-min))
  576. (count-matches regexp (or start 1) (or end (point-max))))))
  577. (defun s-count-matches-all (regexp s &optional start end)
  578. "Count occurrences of `regexp' in `s'.
  579. `start', inclusive, and `end', exclusive, delimit the part of `s' to
  580. match. `start' and `end' are both indexed starting at 1; the initial
  581. character in `s' is index 1.
  582. This function starts looking for the next match from the second
  583. character of the previous match. Hence, it counts matches that
  584. overlap a previously found match. To ignore matches that overlap a
  585. previously found match, use `s-count-matches'."
  586. (declare (side-effect-free t))
  587. (let* ((anchored-regexp (format "^%s" regexp))
  588. (match-count 0)
  589. (i 0)
  590. (narrowed-s (substring s
  591. (when start (1- start))
  592. (when end (1- end)))))
  593. (save-match-data
  594. (while (< i (length narrowed-s))
  595. (when (s-matches? anchored-regexp (substring narrowed-s i))
  596. (setq match-count (1+ match-count)))
  597. (setq i (1+ i))))
  598. match-count))
  599. (defun s-wrap (s prefix &optional suffix)
  600. "Wrap string S with PREFIX and optionally SUFFIX.
  601. Return string S with PREFIX prepended. If SUFFIX is present, it
  602. is appended, otherwise PREFIX is used as both prefix and
  603. suffix."
  604. (declare (pure t) (side-effect-free t))
  605. (concat prefix s (or suffix prefix)))
  606. ;;; Aliases
  607. (defalias 's-blank-p 's-blank?)
  608. (defalias 's-blank-str-p 's-blank-str?)
  609. (defalias 's-capitalized-p 's-capitalized?)
  610. (defalias 's-contains-p 's-contains?)
  611. (defalias 's-ends-with-p 's-ends-with?)
  612. (defalias 's-equals-p 's-equals?)
  613. (defalias 's-less-p 's-less?)
  614. (defalias 's-lowercase-p 's-lowercase?)
  615. (defalias 's-matches-p 's-matches?)
  616. (defalias 's-mixedcase-p 's-mixedcase?)
  617. (defalias 's-numeric-p 's-numeric?)
  618. (defalias 's-prefix-p 's-starts-with?)
  619. (defalias 's-prefix? 's-starts-with?)
  620. (defalias 's-present-p 's-present?)
  621. (defalias 's-starts-with-p 's-starts-with?)
  622. (defalias 's-suffix-p 's-ends-with?)
  623. (defalias 's-suffix? 's-ends-with?)
  624. (defalias 's-uppercase-p 's-uppercase?)
  625. (provide 's)
  626. ;;; s.el ends here