Emacs shell-mode: Prevent RET sending input from anywhere - emacs

As the documentation says that RET will comint-send-input anywhere in a shell mode. The issue is that if you by mistake hit enter on any line and you are not at a prompt it will execute the whole random text until the next prompt. How can I prevent this from happening? It would be nice if hitting Enter anywhere out of the prompt will send you to a new prompt at the bottom.

Something like this?
(defun my-comint-send-input-maybe ()
"Only `comint-send-input' when point is after the latest prompt.
Otherwise move to the end of the buffer."
(interactive)
(let ((proc (get-buffer-process (current-buffer))))
(if (and proc (>= (point) (marker-position (process-mark proc))))
(comint-send-input)
(goto-char (point-max)))))
(with-eval-after-load "comint"
(define-key shell-mode-map [remap comint-send-input] 'my-comint-send-input-maybe))
You could replace (goto-char (point-max)) with (comint-copy-old-input) to insert but not send the old input at the new prompt; but that's still liable to cause problems when the inserted input looks like output.
However, also note the comments and link in C-hf comint-send-input regarding comint-get-old-input -- this can be used to implement custom logic for establishing what the "old input" should be when comint-send-input is invoked with point before the process mark.

Bulletproof:
(defun comint-send-input-or-insert-previous-input ()
"Call `comint-send-input' if point is after the process output marker.
Otherwise, move point to the process mark and try to insert a previous input
from `comint-input-ring' (if any) returned by `comint-previous-input-string'
and affected by the current value of `comint-input-ring-index'.
Implementation is synthesized from and inspired by the `comint-after-pmark-p',
`comint-goto-process-mark', and `comint-copy-old-input' functions."
(interactive)
(let ((process (get-buffer-process (current-buffer))))
(if (not process)
(user-error "Current buffer has no process")
(let ((pmark (process-mark process)))
(if (<= (marker-position pmark) (point))
(comint-send-input)
(goto-char pmark)
(when (and (eolp) comint-input-ring)
(let ((input (comint-previous-input-string 0)))
(when (char-or-string-p input)
(insert input)))))))))

Related

What's wrong with this elisp function?

I write a elisp function to copy the current line if no region has be selected, but it does not work on emacs 24.5. When I hit the "M-w" keystrokes , there comes a message "Mark set" in the minibuffer. Did I miss something?
(defun copy-region-or-current-line (beg end)
"copy current if no region selected, copy the region otherwise"
(interactive "r")
(let ((cur-pos (point)))
(if (region-active-p)
(kill-ring-save beg end)
(progn
(kill-whole-line)
(yank)
(goto-char cur-pos)))))
(global-set-key (kbd "M-w") 'copy-region-or-current-line)
Your function works: You're calling yank and that command sets the mark; hence the message.
That's a side effect you undoubtedly don't want, though, and the kill+yank sequence isn't necessary.
You already know about kill-ring-save, so just use that with (line-beginning-position) and (line-end-position).
FYI, on account of the optional REGION argument to kill-ring-save, you could rewrite this as:
(defun copy-region-or-current-line ()
"Copy the active region or the current line to the kill ring."
(interactive)
(if (region-active-p)
(kill-ring-save nil nil t)
(kill-ring-save (line-beginning-position) (line-end-position))))

Emacs: what is the conventional way of receiving output from a process?

My aim is to get the output from a process in Emacs.
For example, M-x run-python gives me a python shell *Python* that I can send python code to. If I send print "hello world" to *Python*, I hope Emacs can know the result once the execution is finished and echo it in the mini-buffer.
Is it possible to add something like a callback?
Thanks to the comments from #lawlist , I solved my problem by creating the following filter function and assigning it to the process (*MozRepl* in my case) with (set-process-filter (get-buffer-process "*MozRepl*") 'moz-controller-repl-filter)
(defun moz-controller-repl-filter (proc string)
"Filter function of *MozRepl*.
It gets the useful output of *MozRepl*, store it in `moz-controller-repl-output` and `kill-ring`"
(when (buffer-live-p (process-buffer proc))
(unless (string= string "repl> ") ; ignore empty output (page up, page down, etc)
(setq moz-controller-repl-output
(replace-regexp-in-string "\"\\(.+\\)\"\nrepl> " "\\1" string))
(kill-new moz-controller-repl-output) ; append to kill-ring
(message moz-controller-repl-output) ; show the copied content in echo area
)
(with-current-buffer (process-buffer proc)
(let ((moving (= (point) (process-mark proc))))
(save-excursion
;; Insert the text, advancing the process marker.
(goto-char (process-mark proc))
(insert string)
(set-marker (process-mark proc) (point)))
(if moving (goto-char (process-mark proc)))))))

Running command line commands in Emacs, and receiving their output

I want to run a set of command line commands in a loop within emacs, with the loop stopping when the user taps a key.
This is in order to see an ascii 'video' appear in Emacs, which stops when you press a key.
I thought it would be fun to have image-to-ascii bit of text as a comment (with the image coming from my mac's camera).
I use imagesnap to take the camera image, and jp2a to convert it to ascii. I think imagesnap is mac only. Here's the code I have so far:
(defun ascii-video-comment ()
"Makes video comment, requires imagemagick, jp2a, imagesnap"
(interactive)
(shell-command "imagesnap -q ~/Desktop/emacs-snap.jpg")
(insert (shell-command-to-string "jp2a --width=48 ~/Desktop/emacs-snap.jpg"))
(shell-command "rm ~/Desktop/emacs-snap.jpg")
)
This just takes a snap from the camera, converts to ascii, inserts it into my file, and places the cursor after.
Like I say, I would like it to keep looping, giving the appearance of a slow ascii video, until i tap a key to select the current 'frame'.
Is this even possible?
EDIT
This is my current code, which I'm fairly happy with. It loops 20 times, and you can choose the current image by cancelling (C-g). Things seem to go wrong when you do it a second time though.
(defun ascii-video-comment ()
"Makes video comment, requires imagemagick, jp2a, imagesnap"
(interactive)
(cl-loop repeat 20 do
(shell-command "imagesnap -q ~/Desktop/ascii-video-comment.jpg")
(cua-set-mark)
(insert (shell-command-to-string "jp2a --width=120 ~/Desktop/ascii-video-comment.jpg"))
(shell-command "rm ~/Desktop/ascii-video-comment.jpg")
(comment-region (mark) (point))
(cua-set-mark)
(pop-global-mark)
(sit-for 0.1)
(undo)
)
)
On your EDIT "final code": don't use interactive commands in a lisp program: you code becomes brittle and inefficient.
E.g., the doc string for shell-command (C-h f shell-command RET) explicitly states:
In Elisp, you will often be better served by calling call-process or
start-process directly, since it offers more control and does not
impose the use of a shell (with its need to quote arguments)
Also, use delete-file instead of (shell-command "rm ...").
Do not use cua-set-mark, pop-global-mark, and, especially, undo in programs.
Bind a variable instead:
(let ((beg (point)))
(call-process "jp2a" nil t t "--width=120" "~/Desktop/ascii-video-comment.jpg")
(comment-region beg (point))
(sit-for 0.1)
(delete-region beg (point)))
AFAIR, Emacs doesn't provide API to poll for pending events, so there are two options. UPD: disregard that, should've read the manual beforehand, Emacs does provide API to poll for pending events:
(defun start-printing-messages-2 ()
(interactive)
(while (not (input-pending-p))
(loop-body-function)
(redisplay 'force)))
If you want a delay between command execution, there's sit-for for you:
(defun start-printing-messages-3 ()
(interactive)
(while (sit-for 0.05)
(loop-body-function)))
If you want that delay to start counting from beginning of loop body rather than its end (if your loop body might take significant time), you need to set up full-fledged timer execution: you basically run a function in a timer and add a post-command-hook that will kill that timer:
(defvar loop-run-count 0)
(defvar loop-timer-object nil)
(defun loop-body-function ()
(setq loop-run-count (1+ loop-run-count))
(message "The function was run %s times" loop-run-count))
(defun stop-printing-messages ()
(when loop-timer-object
(cancel-timer loop-timer-object)
(remove-hook 'post-command-hook 'stop-printing-messages)))
(defun start-printing-messages ()
(interactive)
(setq loop-run-count 0)
;; post-command-hook is added via timer too, because otherwise it
;; might get called right after this function completes and this
;; would kill the timer that didn't even start yet.
;; get killed right after creation.
(run-with-timer
0.01 nil (lambda ()
(add-hook 'post-command-hook 'stop-printing-messages)))
(setq loop-timer-object
(run-with-timer nil 0.01 'loop-body-function)))
You can wait for input with while-no-input and sit-for.
For the use case you describe, sit-for is what you need.
Note that you should combine the two shell calls with && or make a shell
script.
Here is a toy command that does what you need, but only flashing random numbers.
(defun flash-me ()
"flash random number until you press a key"
(interactive)
(let ((beg (copy-marker (point)))
(end (copy-marker (point) t)))
(loop do (progn
(delete-region beg end)
(insert (shell-command-to-string "echo $RANDOM")))
while (sit-for 1))
(set-marker beg nil)
(set-marker end nil)))

Disable auto-fill-mode locally (or un fill-paragraph) with emacs

I use M-q for fill-paragraph, can I do the un-fill-paragraph in auto-fill-mode?
With org mode, I sometimes enter [[Very long HTML][Name with spaces]], and for the 'Name with spaces' the auto-fill mode break the whole line based on the inserted space, which makes it very ugly.
Is there a command something like un-fill-paragraph? Or, is there a way disable auto-fill-mode temporarily/locally?
Emacs does not record what was your line before calling fill-paragraph. So the only thing you can do is C-_ which runs the command undo. It can undo your fill-paragraph command but only if it is the preceding command call.
If you want to put a multi-line paragraph on one line you could do like this :
Select the region
C-M-% C-q C-j RET SPACE RET !
Xah Lee has updated his code since monotux's answer, and I refactored it somewhat for readability:
(defun my-toggle-fill-paragraph ()
;; Based on http://xahlee.org/emacs/modernization_fill-paragraph.html
"Fill or unfill the current paragraph, depending upon the current line length.
When there is a text selection, act on the region.
See `fill-paragraph' and `fill-region'."
(interactive)
;; We set a property 'currently-filled-p on this command's symbol
;; (i.e. on 'my-toggle-fill-paragraph), thus avoiding the need to
;; create a variable for remembering the current fill state.
(save-excursion
(let* ((deactivate-mark nil)
(line-length (- (line-end-position) (line-beginning-position)))
(currently-filled (if (eq last-command this-command)
(get this-command 'currently-filled-p)
(< line-length fill-column)))
(fill-column (if currently-filled
most-positive-fixnum
fill-column)))
(if (region-active-p)
(fill-region (region-beginning) (region-end))
(fill-paragraph))
(put this-command 'currently-filled-p (not currently-filled)))))
To remake a long line out of a paragraph in Org mode, I gave myself a new command. Here is the associated Emacs Lisp code:
(defun fp-unfill-paragraph (&optional justify region)
(interactive (progn
(barf-if-buffer-read-only)
(list (if current-prefix-arg 'full) t)))
(interactive)
(let ((fill-column 100000))
(fill-paragraph justify region)))
(global-set-key "\C-ceu" 'fp-unfill-paragraph)
Of course, you adjust the command keybinding as you see fit!
I use the following snippet to fill and un-fill paragraphs (using only M-q), it is really, really handy. I borrowed it from Xah Lee, but removed some comments and whitespace in order to make it fit in here. The link in the first comment goes to his original code.
;; http://xahlee.org/emacs/modernization_fill-paragraph.html
(defun compact-uncompact-block ()
"Remove or add line endings on the current block of text.
This is similar to a toggle for fill-paragraph and unfill-paragraph
When there is a text selection, act on the region.
When in text mode, a paragraph is considered a block. When in programing
language mode, the block defined by between empty lines.
Todo: The programing language behavior is currently not done.
Right now, the code uses fill* functions, so does not work or work well
in programing lang modes. A proper implementation to compact is replacing
newline chars by space when the newline char is not inside string.
"
(interactive)
(let (bds currentLineCharCount currentStateIsCompact
(bigFillColumnVal 4333999) (deactivate-mark nil))
(save-excursion
(setq currentLineCharCount
(progn
(setq bds (bounds-of-thing-at-point 'line))
(length (buffer-substring-no-properties (car bds) (cdr bds)))))
(setq currentStateIsCompact
(if (eq last-command this-command)
(get this-command 'stateIsCompact-p)
(if (> currentLineCharCount fill-column) t nil)))
(if (and transient-mark-mode mark-active)
(if currentStateIsCompact
(fill-region (region-beginning) (region-end))
(let ((fill-column bigFillColumnVal))
(fill-region (region-beginning) (region-end)))
)
(if currentStateIsCompact
(fill-paragraph nil)
(let ((fill-column bigFillColumnVal))
(fill-paragraph nil))))
(put this-command 'stateIsCompact-p
(if currentStateIsCompact
nil t)))))
(global-set-key (kbd "M-q") 'compact-uncompact-block)

Emacs Lisp buffer not running font lock mode until opened by user

My problem is I am opening a buffer using (set-buffer (find-tag-noselect (current-word))) and then I try to copy some text out of that buffer. The text that I get back has only the properties (fontified nil). find-tag-noselect automatically opens the buffer found in the TAGS file but it seems it does not run the font lock mode over it. When I manually switch to this buffer after it has been opened and then run the function again when it copies the text it has all the correct text properties attached. So what do I need to do to have this buffer completely initialized so that the correct syntax highlighting will be copied in?
(defvar newline-string "
")
(defun get-initial-indent-regexp-python()
"Gets the initial amount of spaces for the function we are looking at, does not account for tabs"
(concat "^" (get-current-indent-string) (concat "[^ #" newline-string "]")))
(defun get-end-of-function-python(spaces-regex)
"Gets the point at the end of a python block"
(save-excursion
(forward-line 1)
(while (and (not (looking-at spaces-regex)) (equal (forward-line 1) 0)))
(point)))
(defun get-point-at-end-of-function ()
"This might be better served checking the major mode."
(setq extension (file-name-extension (buffer-file-name)))
(if (equal extension "py")
(get-end-of-function-python (get-initial-indent-regexp-python))))
(defun inline-function ()
"Must change to overlays, be able to toggle visibility"
(interactive)
(let (text indent-string)
; clean all overlays without attached buffer
(save-excursion
(set-buffer (find-tag-noselect (current-word)))
(setq text (buffer-substring (point) (get-point-at-end-of-function))))
(setq text (concat newline-string text))
(save-excursion
(move-end-of-line nil)
(let (overlay)
(setq overlay (make-overlay (point) (+ (point) 1) (current-buffer)))
(overlay-put overlay 'display text)
(setq inline-func-overlays (cons overlay inline-func-overlays))))))
What's happening is that font-lock is done on-the-fly, so only the displayed parts of the buffer get "fontified". If you want/need to overrule this optimization, you need different functions depending on the circumstance (depending on how font-lock happens to be configured). We should add a new font-lock-ensure-fontified function for that, but in the mean time, you can take ps-print-.el as an example:
(defun ps-print-ensure-fontified (start end)
(cond ((and (boundp 'jit-lock-mode) (symbol-value 'jit-lock-mode))
(jit-lock-fontify-now start end))
((and (boundp 'lazy-lock-mode) (symbol-value 'lazy-lock-mode))
(lazy-lock-fontify-region start end))))
I'm not exactly sure what you're trying to do, but set-buffer does not display the buffer, so its effect ends when the current command terminates. It's generally useful only for temporary buffer switches inside a function and I guess this is the reason it doesn't run font-lock on the buffer. When you manually go to the buffer you're probably using a different function - switch-to-buffer.
Try explicitly calling 'font-lock-fontify-buffer'.