diff options
author | Yuuki Harano <masm+github@masm11.me> | 2021-07-04 22:37:03 +0900 |
---|---|---|
committer | Yuuki Harano <masm+github@masm11.me> | 2021-07-04 22:37:03 +0900 |
commit | 492a0ae5927eda83b65dd08d3e1655a62fc2c43d (patch) | |
tree | 8bb6a39483236c3a4574c93b37b0a81b8f639bb0 /lisp/emacs-lisp | |
parent | 01b0a909b5ca858a09484821cc866127652f4153 (diff) | |
parent | 2f2afa0b310bbce43a8703f5467b2638082abdd9 (diff) | |
download | emacs-492a0ae5927eda83b65dd08d3e1655a62fc2c43d.tar.gz emacs-492a0ae5927eda83b65dd08d3e1655a62fc2c43d.tar.bz2 emacs-492a0ae5927eda83b65dd08d3e1655a62fc2c43d.zip |
Merge branch 'master' of git.sv.gnu.org:/srv/git/emacs into feature/pgtk
Diffstat (limited to 'lisp/emacs-lisp')
-rw-r--r-- | lisp/emacs-lisp/bytecomp.el | 134 | ||||
-rw-r--r-- | lisp/emacs-lisp/cl-extra.el | 15 | ||||
-rw-r--r-- | lisp/emacs-lisp/cl-macs.el | 9 | ||||
-rw-r--r-- | lisp/emacs-lisp/cl-preloaded.el | 21 | ||||
-rw-r--r-- | lisp/emacs-lisp/crm.el | 3 | ||||
-rw-r--r-- | lisp/emacs-lisp/easy-mmode.el | 18 | ||||
-rw-r--r-- | lisp/emacs-lisp/ert.el | 21 | ||||
-rw-r--r-- | lisp/emacs-lisp/find-func.el | 10 | ||||
-rw-r--r-- | lisp/emacs-lisp/lisp-mnt.el | 26 | ||||
-rw-r--r-- | lisp/emacs-lisp/lisp-mode.el | 2 | ||||
-rw-r--r-- | lisp/emacs-lisp/package.el | 3 | ||||
-rw-r--r-- | lisp/emacs-lisp/shortdoc.el | 9 | ||||
-rw-r--r-- | lisp/emacs-lisp/subr-x.el | 1 |
13 files changed, 155 insertions, 117 deletions
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el index 472e0ba3ba3..3e65db42421 100644 --- a/lisp/emacs-lisp/bytecomp.el +++ b/lisp/emacs-lisp/bytecomp.el @@ -2066,73 +2066,73 @@ See also `emacs-lisp-byte-compile-and-load'." (message "Compiling %s...done" filename)) (kill-buffer input-buffer) (with-current-buffer output-buffer - (goto-char (point-max)) - (insert "\n") ; aaah, unix. - (cond - ((null target-file) nil) ;We only wanted the warnings! - ((and (or (null byte-native-compiling) - (and byte-native-compiling byte+native-compile)) - (file-writable-p target-file) - ;; We attempt to create a temporary file in the - ;; target directory, so the target directory must be - ;; writable. - (file-writable-p - (file-name-directory - ;; Need to expand in case TARGET-FILE doesn't - ;; include a directory (Bug#45287). - (expand-file-name target-file)))) - ;; We must disable any code conversion here. - (let* ((coding-system-for-write 'no-conversion) - ;; Write to a tempfile so that if another Emacs - ;; process is trying to load target-file (eg in a - ;; parallel bootstrap), it does not risk getting a - ;; half-finished file. (Bug#4196) - (tempfile - (make-temp-file (when (file-writable-p target-file) - (expand-file-name target-file)))) - (default-modes (default-file-modes)) - (temp-modes (logand default-modes #o600)) - (desired-modes (logand default-modes #o666)) - (kill-emacs-hook - (cons (lambda () (ignore-errors - (delete-file tempfile))) - kill-emacs-hook))) - (unless (= temp-modes desired-modes) - (set-file-modes tempfile desired-modes 'nofollow)) - (write-region (point-min) (point-max) tempfile nil 1) - ;; This has the intentional side effect that any - ;; hard-links to target-file continue to - ;; point to the old file (this makes it possible - ;; for installed files to share disk space with - ;; the build tree, without causing problems when - ;; emacs-lisp files in the build tree are - ;; recompiled). Previously this was accomplished by - ;; deleting target-file before writing it. - (if byte-native-compiling - ;; Defer elc final renaming. - (setf byte-to-native-output-file - (cons tempfile target-file)) - (rename-file tempfile target-file t))) - (or noninteractive - byte-native-compiling - (message "Wrote %s" target-file))) - ((file-writable-p target-file) - ;; In case the target directory isn't writable (see e.g. Bug#44631), - ;; try writing to the output file directly. We must disable any - ;; code conversion here. - (let ((coding-system-for-write 'no-conversion)) - (with-file-modes (logand (default-file-modes) #o666) - (write-region (point-min) (point-max) target-file nil 1))) - (or noninteractive (message "Wrote %s" target-file))) - (t - ;; This is just to give a better error message than write-region - (let ((exists (file-exists-p target-file))) - (signal (if exists 'file-error 'file-missing) - (list "Opening output file" - (if exists - "Cannot overwrite file" - "Directory not writable or nonexistent") - target-file))))) + (when (and target-file + (or (not byte-native-compiling) + (and byte-native-compiling byte+native-compile))) + (goto-char (point-max)) + (insert "\n") ; aaah, unix. + (cond + ((and (file-writable-p target-file) + ;; We attempt to create a temporary file in the + ;; target directory, so the target directory must be + ;; writable. + (file-writable-p + (file-name-directory + ;; Need to expand in case TARGET-FILE doesn't + ;; include a directory (Bug#45287). + (expand-file-name target-file)))) + ;; We must disable any code conversion here. + (let* ((coding-system-for-write 'no-conversion) + ;; Write to a tempfile so that if another Emacs + ;; process is trying to load target-file (eg in a + ;; parallel bootstrap), it does not risk getting a + ;; half-finished file. (Bug#4196) + (tempfile + (make-temp-file (when (file-writable-p target-file) + (expand-file-name target-file)))) + (default-modes (default-file-modes)) + (temp-modes (logand default-modes #o600)) + (desired-modes (logand default-modes #o666)) + (kill-emacs-hook + (cons (lambda () (ignore-errors + (delete-file tempfile))) + kill-emacs-hook))) + (unless (= temp-modes desired-modes) + (set-file-modes tempfile desired-modes 'nofollow)) + (write-region (point-min) (point-max) tempfile nil 1) + ;; This has the intentional side effect that any + ;; hard-links to target-file continue to + ;; point to the old file (this makes it possible + ;; for installed files to share disk space with + ;; the build tree, without causing problems when + ;; emacs-lisp files in the build tree are + ;; recompiled). Previously this was accomplished by + ;; deleting target-file before writing it. + (if byte-native-compiling + ;; Defer elc final renaming. + (setf byte-to-native-output-file + (cons tempfile target-file)) + (rename-file tempfile target-file t))) + (or noninteractive + byte-native-compiling + (message "Wrote %s" target-file))) + ((file-writable-p target-file) + ;; In case the target directory isn't writable (see e.g. Bug#44631), + ;; try writing to the output file directly. We must disable any + ;; code conversion here. + (let ((coding-system-for-write 'no-conversion)) + (with-file-modes (logand (default-file-modes) #o666) + (write-region (point-min) (point-max) target-file nil 1))) + (or noninteractive (message "Wrote %s" target-file))) + (t + ;; This is just to give a better error message than write-region + (let ((exists (file-exists-p target-file))) + (signal (if exists 'file-error 'file-missing) + (list "Opening output file" + (if exists + "Cannot overwrite file" + "Directory not writable or nonexistent") + target-file)))))) (kill-buffer (current-buffer))) (if (and byte-compile-generate-call-tree (or (eq t byte-compile-generate-call-tree) diff --git a/lisp/emacs-lisp/cl-extra.el b/lisp/emacs-lisp/cl-extra.el index eabba27d229..3840d13ecff 100644 --- a/lisp/emacs-lisp/cl-extra.el +++ b/lisp/emacs-lisp/cl-extra.el @@ -847,7 +847,7 @@ PROPLIST is a list of the sort returned by `symbol-plist'. "\n"))) "\n")) -(defun cl--print-table (header rows) +(defun cl--print-table (header rows &optional last-slot-on-next-line) ;; FIXME: Isn't this functionality already implemented elsewhere? (let ((cols (apply #'vector (mapcar #'string-width header))) (col-space 2)) @@ -877,7 +877,11 @@ PROPLIST is a list of the sort returned by `symbol-plist'. header)) "\n") (dolist (row rows) - (insert (apply #'format format row) "\n")))))) + (insert (apply #'format format row) "\n") + (when last-slot-on-next-line + (dolist (line (string-lines (car (last row)))) + (insert " " line "\n")) + (insert "\n"))))))) (defun cl--describe-class-slots (class) "Print help description for the slots in CLASS. @@ -897,14 +901,13 @@ Outputs to the current buffer." (list (cl-prin1-to-string (cl--slot-descriptor-name slot)) (cl-prin1-to-string (cl--slot-descriptor-type slot)) (cl-prin1-to-string (cl--slot-descriptor-initform slot)) - (let ((doc (plist-get (cl--slot-descriptor-props slot) - :documentation))) + (let ((doc (alist-get :documentation + (cl--slot-descriptor-props slot)))) (if (not doc) "" (setq has-doc t) (substitute-command-keys doc))))) slots))) - (cl--print-table `("Name" "Type" "Default" . ,(if has-doc '("Doc"))) - slots-strings)) + (cl--print-table `("Name" "Type" "Default") slots-strings has-doc)) (insert "\n") (when (> (length cslots) 0) (insert (propertize "\nClass Allocated Slots:\n\n" 'face 'bold)) diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el index a59d42e673c..cff43689405 100644 --- a/lisp/emacs-lisp/cl-macs.el +++ b/lisp/emacs-lisp/cl-macs.el @@ -3276,6 +3276,13 @@ STRUCT-TYPE is a symbol naming a struct type. Return `record', (declare (side-effect-free t) (pure t)) (cl--struct-class-type (cl--struct-get-class struct-type))) +(defun cl--alist-to-plist (alist) + (let ((res '())) + (dolist (x alist) + (push (car x) res) + (push (cdr x) res)) + (nreverse res))) + (defun cl-struct-slot-info (struct-type) "Return a list of slot names of struct STRUCT-TYPE. Each entry is a list (SLOT-NAME . OPTS), where SLOT-NAME is a @@ -3293,7 +3300,7 @@ slots skipped by :initial-offset may appear in the list." ,(cl--slot-descriptor-initform slot) ,@(if (not (eq (cl--slot-descriptor-type slot) t)) `(:type ,(cl--slot-descriptor-type slot))) - ,@(cl--slot-descriptor-props slot)) + ,@(cl--alist-to-plist (cl--slot-descriptor-props slot))) descs))) (nreverse descs))) diff --git a/lisp/emacs-lisp/cl-preloaded.el b/lisp/emacs-lisp/cl-preloaded.el index 7365e23186a..ef60b266f9e 100644 --- a/lisp/emacs-lisp/cl-preloaded.el +++ b/lisp/emacs-lisp/cl-preloaded.el @@ -124,12 +124,11 @@ supertypes from the most specific to least specific.") (get name 'cl-struct-print)) (cl--find-class name))))) -(defun cl--plist-remove (plist member) - (cond - ((null plist) nil) - ((null member) plist) - ((eq plist member) (cddr plist)) - (t `(,(car plist) ,(cadr plist) ,@(cl--plist-remove (cddr plist) member))))) +(defun cl--plist-to-alist (plist) + (let ((res '())) + (while plist + (push (cons (pop plist) (pop plist)) res)) + (nreverse res))) (defun cl--struct-register-child (parent tag) ;; Can't use (cl-typep parent 'cl-structure-class) at this stage @@ -164,12 +163,14 @@ supertypes from the most specific to least specific.") (i 0) (offset (if type 0 1))) (dolist (slot slots) - (let* ((props (cddr slot)) - (typep (plist-member props :type)) - (type (if typep (cadr typep) t))) + (let* ((props (cl--plist-to-alist (cddr slot))) + (typep (assq :type props)) + (type (if (null typep) t + (setq props (delq typep props)) + (cdr typep)))) (aset v i (cl--make-slot-desc (car slot) (nth 1 slot) - type (cl--plist-remove props typep)))) + type props))) (puthash (car slot) (+ i offset) index-table) (cl-incf i)) v)) diff --git a/lisp/emacs-lisp/crm.el b/lisp/emacs-lisp/crm.el index e106815817e..d24ea355a51 100644 --- a/lisp/emacs-lisp/crm.el +++ b/lisp/emacs-lisp/crm.el @@ -183,8 +183,7 @@ Return t if the current element is now a valid match; otherwise return nil." Like `minibuffer-complete-word' but for `completing-read-multiple'." (interactive) (crm--completion-command beg end - (completion-in-region--single-word - beg end minibuffer-completion-table minibuffer-completion-predicate))) + (completion-in-region--single-word beg end))) (defun crm-complete-and-exit () "If all of the minibuffer elements are valid completions then exit. diff --git a/lisp/emacs-lisp/easy-mmode.el b/lisp/emacs-lisp/easy-mmode.el index 0a6d4ec504e..3a00fdb454d 100644 --- a/lisp/emacs-lisp/easy-mmode.el +++ b/lisp/emacs-lisp/easy-mmode.el @@ -84,18 +84,22 @@ replacing its case-insensitive matches with the literal string in LIGHTER." (defconst easy-mmode--arg-docstring " -If called interactively, toggle `%s'. If the prefix argument is -positive, enable the mode, and if it is zero or negative, disable -the mode. +This is a minor mode. If called interactively, toggle the `%s' +mode. If the prefix argument is positive, enable the mode, and +if it is zero or negative, disable the mode. If called from Lisp, toggle the mode if ARG is `toggle'. Enable the mode if ARG is nil, omitted, or is a positive number. Disable the mode if ARG is a negative number. +To check whether the minor mode is enabled in the current buffer, +evaluate `%S'. + The mode's hook is called both when the mode is enabled and when it is disabled.") -(defun easy-mmode--mode-docstring (doc mode-pretty-name keymap-sym) +(defun easy-mmode--mode-docstring (doc mode-pretty-name keymap-sym + getter) (let ((doc (or doc (format "Toggle %s on or off. \\{%s}" mode-pretty-name keymap-sym)))) @@ -104,7 +108,8 @@ it is disabled.") (let* ((fill-prefix nil) (docs-fc (bound-and-true-p emacs-lisp-docstring-fill-column)) (fill-column (if (integerp docs-fc) docs-fc 65)) - (argdoc (format easy-mmode--arg-docstring mode-pretty-name)) + (argdoc (format easy-mmode--arg-docstring mode-pretty-name + getter)) (filled (if (fboundp 'fill-region) (with-temp-buffer (insert argdoc) @@ -308,7 +313,8 @@ or call the function `%s'.")))) ,(funcall warnwrap `(defun ,modefun (&optional arg ,@extra-args) - ,(easy-mmode--mode-docstring doc pretty-name keymap-sym) + ,(easy-mmode--mode-docstring doc pretty-name keymap-sym + getter) ,(when interactive ;; Use `toggle' rather than (if ,mode 0 1) so that using ;; repeat-command still does the toggling correctly. diff --git a/lisp/emacs-lisp/ert.el b/lisp/emacs-lisp/ert.el index 6793b374eea..92acfe7246f 100644 --- a/lisp/emacs-lisp/ert.el +++ b/lisp/emacs-lisp/ert.el @@ -313,12 +313,13 @@ It should only be stopped when ran from inside ert--run-test-internal." (list :form `(,,fn ,@,args)) (unless (eql ,value ',default-value) (list :value ,value)) - (let ((-explainer- - (and (symbolp ',fn-name) - (get ',fn-name 'ert-explainer)))) - (when -explainer- - (list :explanation - (apply -explainer- ,args))))) + (unless (eql ,value ',default-value) + (let ((-explainer- + (and (symbolp ',fn-name) + (get ',fn-name 'ert-explainer)))) + (when -explainer- + (list :explanation + (apply -explainer- ,args)))))) value) ,value)))))))) @@ -1300,7 +1301,7 @@ empty string." "Pretty-print OBJECT, indenting it to the current column of point. Ensures a final newline is inserted." (let ((begin (point)) - (pp-escape-newlines nil) + (pp-escape-newlines t) (print-escape-control-characters t)) (pp object (current-buffer)) (unless (bolp) (insert "\n")) @@ -1551,7 +1552,7 @@ Ran \\([0-9]+\\) tests, \\([0-9]+\\) results as expected\ (when badtests (message "%d files did not finish:" (length badtests)) (mapc (lambda (l) (message " %s" l)) badtests) - (if (getenv "EMACS_HYDRA_CI") + (if (or (getenv "EMACS_HYDRA_CI") (getenv "EMACS_EMBA_CI")) (with-temp-buffer (dolist (f badtests) (erase-buffer) @@ -1567,8 +1568,8 @@ Ran \\([0-9]+\\) tests, \\([0-9]+\\) results as expected\ (setq tests (sort tests (lambda (x y) (> (car x) (car y))))) (when (< high (length tests)) (setcdr (nthcdr (1- high) tests) nil)) (message "%s" (mapconcat #'cdr tests "\n"))) - ;; More details on hydra, where the logs are harder to get to. - (when (and (getenv "EMACS_HYDRA_CI") + ;; More details on hydra and emba, where the logs are harder to get to. + (when (and (or (getenv "EMACS_HYDRA_CI") (getenv "EMACS_EMBA_CI")) (not (zerop (+ nunexpected nskipped)))) (message "\nDETAILS") (message "-------") diff --git a/lisp/emacs-lisp/find-func.el b/lisp/emacs-lisp/find-func.el index 58876a45e19..7bc3e6b25ff 100644 --- a/lisp/emacs-lisp/find-func.el +++ b/lisp/emacs-lisp/find-func.el @@ -123,10 +123,18 @@ should insert the feature name." :group 'xref :version "25.1") +(defun find-function--defface (symbol) + (catch 'found + (while (re-search-forward (format find-face-regexp symbol) nil t) + (unless (ppss-comment-or-string-start + (save-excursion (syntax-ppss (match-beginning 0)))) + ;; We're not in a comment or a string. + (throw 'found t))))) + (defvar find-function-regexp-alist '((nil . find-function-regexp) (defvar . find-variable-regexp) - (defface . find-face-regexp) + (defface . find-function--defface) (feature . find-feature-regexp) (defalias . find-alias-regexp)) "Alist mapping definition types into regexp variables. diff --git a/lisp/emacs-lisp/lisp-mnt.el b/lisp/emacs-lisp/lisp-mnt.el index 73a33a553fb..83da495edf0 100644 --- a/lisp/emacs-lisp/lisp-mnt.el +++ b/lisp/emacs-lisp/lisp-mnt.el @@ -360,10 +360,10 @@ Return argument is of the form (\"HOLDER\" \"YEAR1\" ... \"YEARN\")" "Split up an email address X into full name and real email address. The value is a cons of the form (FULLNAME . ADDRESS)." (cond ((string-match "\\(.+\\) [(<]\\(\\S-+@\\S-+\\)[>)]" x) - (cons (match-string 1 x) + (cons (string-trim-right (match-string 1 x)) (match-string 2 x))) ((string-match "\\(\\S-+@\\S-+\\) [(<]\\(.*\\)[>)]" x) - (cons (match-string 2 x) + (cons (string-trim-right (match-string 2 x)) (match-string 1 x))) ((string-match "\\S-+@\\S-+" x) (cons nil x)) @@ -378,14 +378,22 @@ the cdr is an email address." (let ((authorlist (lm-header-multiline "author"))) (mapcar #'lm-crack-address authorlist)))) +(defun lm-maintainers (&optional file) + "Return the maintainer list of file FILE, or current buffer if FILE is nil. +If the maintainers are unspecified, then return the authors. +Each element of the list is a cons; the car is the full name, +the cdr is an email address." + (lm-with-file file + (mapcar #'lm-crack-address + (or (lm-header-multiline "maintainer") + (lm-header-multiline "author"))))) + (defun lm-maintainer (&optional file) "Return the maintainer of file FILE, or current buffer if FILE is nil. +If the maintainer is unspecified, then return the author. The return value has the form (NAME . ADDRESS)." - (lm-with-file file - (let ((maint (lm-header "maintainer"))) - (if maint - (lm-crack-address maint) - (car (lm-authors)))))) + (declare (obsolete lm-maintainers "28.1")) + (car (lm-maintainers file))) (defun lm-creation-date (&optional file) "Return the created date given in file FILE, or current buffer if FILE is nil." @@ -545,7 +553,7 @@ copyright notice is allowed." "Can't find package name") ((not (lm-authors)) "`Author:' tag missing") - ((not (lm-maintainer)) + ((not (lm-maintainers)) "`Maintainer:' tag missing") ((not (lm-summary)) "Can't find the one-line summary description") @@ -613,7 +621,7 @@ Prompts for bug subject TOPIC. Leaves you in a mail buffer." (interactive "sBug Subject: ") (require 'emacsbug) (let ((package (lm-get-package-name)) - (addr (lm-maintainer)) + (addr (car (lm-maintainers))) (version (lm-version))) (compose-mail (if addr (concat (car addr) " <" (cdr addr) ">") diff --git a/lisp/emacs-lisp/lisp-mode.el b/lisp/emacs-lisp/lisp-mode.el index 59325d647d8..51fb88502ab 100644 --- a/lisp/emacs-lisp/lisp-mode.el +++ b/lisp/emacs-lisp/lisp-mode.el @@ -765,7 +765,7 @@ All commands in `lisp-mode-shared-map' are inherited by this map.") :help "Run an inferior Lisp process, input and output via buffer `*inferior-lisp*'"])) (define-derived-mode lisp-mode lisp-data-mode "Lisp" - "Major mode for editing Lisp code for Lisps other than GNU Emacs Lisp. + "Major mode for editing programs in Common Lisp and other similar Lisps. Commands: Delete converts tabs to spaces as it moves back. Blank lines separate paragraphs. Semicolons start comments. diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el index 5df9b53657b..a0f1ab0ed67 100644 --- a/lisp/emacs-lisp/package.el +++ b/lisp/emacs-lisp/package.el @@ -3374,7 +3374,8 @@ If optional arg BUTTON is non-nil, describe its associated package." (forward-line 1))))) (defvar package--quick-help-keys - '(("install," "delete," "unmark," ("execute" . 1)) + '((("mark for installation," . 9) + ("mark for deletion," . 9) "unmark," ("execute marked actions" . 1)) ("next," "previous") ("Hide-package," "(-toggle-hidden") ("g-refresh-contents," "/-filter," "help"))) diff --git a/lisp/emacs-lisp/shortdoc.el b/lisp/emacs-lisp/shortdoc.el index 16e83074764..4df404015a0 100644 --- a/lisp/emacs-lisp/shortdoc.el +++ b/lisp/emacs-lisp/shortdoc.el @@ -268,6 +268,9 @@ There can be any number of :example/:result elements." :eval (file-name-extension "/tmp/foo.txt")) (file-name-sans-extension :eval (file-name-sans-extension "/tmp/foo.txt")) + (file-name-with-extension + :eval (file-name-with-extension "foo.txt" "bin") + :eval (file-name-with-extension "foo" "bin")) (file-name-base :eval (file-name-base "/tmp/foo.txt")) (file-relative-name @@ -887,7 +890,7 @@ There can be any number of :example/:result elements." (lock-buffer :no-value (lock-buffer "/tmp/foo")) (unlock-buffer - :no-value (lock-buffer))) + :no-value (unlock-buffer))) (define-short-documentation-group overlay "Predicates" @@ -1283,11 +1286,11 @@ Example: (let ((glist (assq group shortdoc--groups))) (unless glist (setq glist (list group)) - (setq shortdoc--groups (append shortdoc--groups (list glist)))) + (push glist shortdoc--groups)) (let ((slist (member section glist))) (unless slist (setq slist (list section)) - (setq slist (append glist slist))) + (nconc glist slist)) (while (and (cdr slist) (not (stringp (cadr slist)))) (setq slist (cdr slist))) diff --git a/lisp/emacs-lisp/subr-x.el b/lisp/emacs-lisp/subr-x.el index 1c13c398dde..468d124c0e2 100644 --- a/lisp/emacs-lisp/subr-x.el +++ b/lisp/emacs-lisp/subr-x.el @@ -317,6 +317,7 @@ than this function." (end (substring string (- (length string) length))) (t (substring string 0 length))))) +;;;###autoload (defun string-lines (string &optional omit-nulls) "Split STRING into a list of lines. If OMIT-NULLS, empty lines will be removed from the results." |