1

I'm running a test suite in a shell buffer that tends to produce really long lines with PASSED or FAILED at the end of them.

I'd like to be able to quickly see whether a given line passed or failed as the text scrolls past, but without throwing away the first part of the line in case. (I have a short script that reads lines and prints the last 80 characters padded on the left with spaces), but I'd prefer to change how the lines are displayed within in emacs so I'm not losing information if I need to inspect a particular test case.

just to be really concrete

1) emacs -q totally stock emacs installation

2) M-x shell start shell

3) M-x toggle-truncate-lines turn off line wrapping

4) run a command like perl -e 'for $x (40..200) { printf "begin%send\n", ("." x $x); }'

You'll see begin...... and no end after the lines become too long for the terminal to display. I'd like the ends to be visible and lined up regardless of the length of the line.

  • This doesn't address the question, but why don't you put the 'PASSED' or 'FAILED' at the start of each line? – phils Sep 26 '17 at 9:28
  • @phils That's how tox (a python script runner) formats the output of unit tests ... I suppose I could use a wrapper script that changes the order of the output to make it easier to scan visually. – Gregory Nisbet Sep 27 '17 at 6:14
  • 2
    Assuming you're running the script via compile then you probably want to use a local compilation-filter-hook to do the processing, and I expect use some kind of text property or overlay to position the text. I'm not familiar with the methods of doing that, I'm afraid. You may want to read up on Margins. Or perhaps even use the Fringe (a green or red bitmap in the right fringe might be quite effective). – phils Sep 27 '17 at 20:03
  • @phils Pityingly right-margin is a bit clumsy to use since this directly modifies the text. It is better to use text properties that do only change the appearance of the text but not its content. It would be great to have a line-postfix text property analogous to line-prefix. The text of line-postfix would appear at the right window boundary instead of the left one. In my answer I've implemented an (almost-)solution to the OP-problem exploiting line-prefix. The only downer is that the text appears at the left window boundary instead of the right one. – Tobias Oct 27 '17 at 11:42
1

It is quite simple to display the line end at the left boundary of the buffer with the help of line-prefix text properties.

I hope that is acceptable for displaying the status of your tests.

The following elisp code defines the minor mode pfx-mode (meaning: line prefix mode). You can define the string to be displayed as line-prefix for each line by setting the option pfx-function to an appropriate function (see the doc for that option). The default for that option is the function pfx-eol which shows a substring taken from the line-end. You can easily define and install your own function instead. Just take a look at pfx-eol as an example for writing your own function.

(defgroup pfx nil
  "Generation of line prefix string by jit-lock."
  :group 'emacs)

(defcustom pfx-function #'pfx-eol
  "Function called with a position POS as argument that should return
the prefix string for the line including POS."
  :group 'pfx
  :type 'function)

(defcustom pfx-eol-length 3
  "Length of the string at end of line that should be shown in the line prefix."
  :group 'pfx
  :type 'number)

(defface pfx-face
  '((t :foreground "red" :background "grey50"))
  "Face for displaying line prefixes."
  :group 'pfx)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun pfx-eol (pos)
  "Return substring of maximal length `pfx-eol-length'
at end of the line containing character position POS."
  (save-excursion
    (goto-char pos)
    (let ((eol (line-end-position))
      (bol (line-beginning-position)))
      (buffer-substring-no-properties (max bol (- eol pfx-eol-length)) eol))))

(defun pfx-update-prefix-at (pos)
  "Update prefix at the line containing POS"
  (let* ((str (propertize (funcall pfx-function pos) 'face 'pfx-face))
     (bol (line-beginning-position))
     (bol1 (1+ bol)))
    (when (> (point-max) bol1)
    (put-text-property bol bol1 'line-prefix str))))

(defun pfx-update-prefix (start end)
  "Update prefix text property of the lines
for region from START to END."
  (pfx-update-prefix-at start)
  (save-excursion
    (goto-char start)
    (while (search-forward "\n" end t)
      (pfx-update-prefix-at (point)))))

(define-minor-mode pfx-mode
  "Show string produced by `pfx-function' as line prefix."
  nil
  " EolP"
  nil
  (if pfx-mode
      (jit-lock-register #'pfx-update-prefix)
    (jit-lock-unregister #'pfx-update-prefix)
    (with-silent-modifications (remove-text-properties 1 (buffer-size) '(line-prefix nil))))
  (jit-lock-refontify))

I've used the following line in a *shell* buffer as test case:

emacs --batch --eval '(send-string-to-terminal (mapconcat (lambda (i) (concat "begin" (make-string i ?.) "end\n")) (number-sequence 40 200) ""))'

The following picture shows a screenshot of emacs after switching on pfx-mode in a shell window and running above test case:

emacs with test case in pfx-mode

1

Try command scroll-left, bound to C-x <.

See also auto-hscroll-mode. You can also set hscroll-margin and hscroll-step.

See the Emacs manual, node Horizontal Scrolling for more information.

For more details, see also the Elisp manual, node Horizontal Scrolling.

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.