0

Currently I'm using (thing-at-point 'line t), however I would like to be able to include the next line(s) as long as they end with a suffix (\ for example).

How to recursively build a string based on the current line, accumulating all others until the suffix is not present?

  • 2
    You could define a symbol with properties forward-op, beginning-op and end-op each pointing to a function that will do the proper thing when thing-at-point calls them. You can see the source of bounds-of-thing-at-point in thingatpt.el to see how these functions will be called. – wvxvw Jul 26 '17 at 9:27
1

If you do not want to delve into the source of thing-at-point, you could simply use a while loop. For example:

(defun my-extract-lines ()
  "Extract line(s) at point. Multiple lines (below the current) are
extracted if they end with a backslash character. Returns the line(s)
as a string with no properties."    
  (interactive)
  (save-excursion
    (let* ((start (line-beginning-position))
           (end start)
           (iterate t)
           (new-end))
      (while iterate
        (setq new-end (line-end-position))
        (if (> new-end end)
            (progn
              (setq end new-end)
              (if (char-equal (char-before end) ?\\)
                  (forward-line)
                (setq iterate nil)))
          (setq iterate nil)))
      (buffer-substring-no-properties start end))))

Another alternative is to use a regex, although it is a little bit complicated (due to the number of backslashes needed). For example:

(defun my-extract-lines ()
  (interactive)
  (let ((str ""))
    (save-excursion
      (beginning-of-line)
      (when (looking-at "\\(\\(?:.*\\\\\n\\)*[^\n]*[^\\\\]$\\)")
        (setq str (match-string 1)))
     str)))
1

Made a modified version of @håkon-hægland's answer, its mostly the same except:

  • It takes a line terminating character.
  • White-space after the terminating character is supported
    (doesn't prevent moving to the next line).
  • The result is joined into a single line with the terminating-char removed from the end of each line.
  • Fixes a bug when the line is at the start of the buffer.

Modified version:

(defun my-extract-lines (line-terminate-char)
  "Extract line(s) at point.
Multiple lines (below the current) are extracted
if they end with line-terminate-char.
Returns the line(s) as a joined string,
without the terminator character and no properties."
  (interactive)
  (save-excursion
    (let* ((start (line-beginning-position))
           (end start)
           (iterate t)
           (new-end))
      (while iterate
        (setq new-end (line-end-position))
        ;; could be more efficient?
        (setq new-end-ws (save-excursion (end-of-line) (skip-syntax-backward "-") (point)))
        (if (> new-end end)
            (progn
              (setq end new-end)
              (setq end-ws new-end-ws)
              (let ((end-ws-before (char-before end-ws)))
                (if (and end-ws-before (char-equal end-ws-before line-terminate-char))
                    (forward-line)
                    (setq iterate nil))))
            (setq iterate nil)))

      ;; OK but we need to remove line-terminate-char and join
      ;; (buffer-substring-no-properties start end)
      (setq line-terminate-str (char-to-string line-terminate-char))
      (mapconcat
       (function
        (lambda (s)
          (string-trim-right (string-remove-suffix line-terminate-str (string-trim s)))))
       (split-string (buffer-substring-no-properties start end) "\n") " "))))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.