1

我想在emacs中循环运行一组命令行命令,当用户点击一个键时循环停止。

这是为了在 Emacs 中看到一个 ascii“视频”,当你按下一个键时它会停止。

我认为将图像到ASCII的文本位作为评论会很有趣(图像来自我的mac相机)。

我使用 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次,可以通过取消(Cg)选择当前图像。但是,当您第二次执行此操作时,事情似乎出错了。

(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)
 )
)
4

3 回答 3

2

在你的EDIT“最终代码”上:不要在 lisp 程序中使用交互式命令:你的代码变得脆弱和低效。例如,shell-command( C-h f shell-command RET) 的文档字符串明确指出:

在 Elisp 中,通过调用call-processstart-process直接为您提供更好的服务,因为它提供了更多控制并且不强制使用 shell(需要引用参数)

另外,使用delete-file代替(shell-command "rm ...").

不要在程序中使用cua-set-markpop-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)))
于 2013-03-20T15:59:52.730 回答
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)))
于 2013-03-20T08:05:36.500 回答
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)))
于 2013-03-20T14:53:23.420 回答