我想在emacs中的循环中运行一组命令行命令,当用户点击一个键时循环停止。
这是为了看到一个ascii'视频'出现在Emacs中,当你按一个键时会停止。
我认为将图像到ascii位的文本作为注释(图像来自我的相机)会很有趣。
我使用imagesnap来拍摄相机图像,使用jp2a将其转换为ascii。我认为imagesnap只是mac。这是我到目前为止的代码:
(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")
)
这只需从相机拍摄,转换为ascii,将其插入到我的文件中,然后将光标放在后面。
就像我说的那样,我希望它能够保持循环,呈现出一个缓慢的ascii视频,直到我点击一个键来选择当前的“帧”。
这甚至可能吗?
修改
这是我目前的代码,我很满意。它循环20次,您可以通过取消(C-g)来选择当前图像。当你第二次这样做时,事情似乎出了问题。
(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)
)
)
答案 0 :(得分:2)
在EDIT
"最终代码":不要在lisp程序中使用交互式命令:代码变得脆弱且效率低下。
例如,shell-command
( C-h f shell-command RET )的文档字符串明确指出:
在Elisp中,通常可以通过致电
call-process
或更好地为您提供服务 直接start-process
,因为它提供更多控制而不是 强制使用shell(需要引用参数)
另外,请使用delete-file
代替(shell-command "rm ...")
。
请勿在程序中使用cua-set-mark
,pop-global-mark
,尤其是undo
。
改为绑定变量:
(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)))
答案 1 :(得分:1)
AFAIR,Emacs不提供API来轮询待处理事件,因此有两个选项。 UPD:忽略这一点,应该事先阅读手册,Emacs确实提供了API轮询待处理事件:
(defun start-printing-messages-2 ()
(interactive)
(while (not (input-pending-p))
(loop-body-function)
(redisplay 'force)))
如果您希望在命令执行之间出现延迟,那么您需要sit-for
:
(defun start-printing-messages-3 ()
(interactive)
(while (sit-for 0.05)
(loop-body-function)))
如果你希望延迟从循环体的开始而不是它的结束开始计数(如果你的循环体可能需要很长时间),你需要设置完整的计时器执行:你基本上在计时器中运行一个函数并添加一个会杀死该计时器的post-command-hook
:
(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)))
答案 2 :(得分:1)
您可以使用while-no-input
和sit-for
等待输入。
对于您描述的用例,sit-for
就是您所需要的。
请注意,您应该将两个shell调用与&&
组合在一起,或者创建一个shell
脚本。
这是一个玩具命令,它可以满足您的需要,但只会闪烁随机数。
(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)))