I have program that runs for long periods of time and I'd like to interrupt it but not with ctrl-c ctrl-c. I also don't want the system to wait for a keystroke every so often. Instead, if I do press a key, I want it to wrap things up and exit. I found listen and read-char-no-hang but I can't get it to work right. Here's what I tried to do
(let ((f nil))
(loop while (not f) do
(if (listen)
(setf f t)))))
Obviously, this is doing less than a sloth on Xanax as far as finding key=-presses. What am I doing wrong?
CCL has multithreading, I believe. You could try spawning a worker thread in the background and have a control thread doing a blocking read, and then communicating via a special variable. The following works in Lispworks, I don't have CCL available. You'd have to translate the mp:process-run-function to whatever CCL uses to spawn threads:
(defparameter *f* nil)
(defun cmd-loop ()
(setf *f* nil)
(mp:process-run-function "work" () #'do-work) ; Spawn worker
(read-char *terminal-io*) ; Blocking read
(setf *f* t))
(defun do-work ()
(loop while (not *f*)
do
(format t "~a " *f*)
(finish-output)))
(cmd-loop)
The big assumption I'm making here is that CCL multithreading works similarily to LW multithreading, so that both threads can access the shared state variable *f*.
I use SLIME for these things.
I usually start lisp on a remote computer like this:
whoplisp#laptop:~$ ssh -L4005:127.0.0.1:4005 remotecomputer
whoplisp#remotecomputer:~$ sbcl
(require :asdf)
(require :swank)
(setf swank:*dedicated-output-stream-port* nil)
(swank:create-server)
Then I can start a slime session on the laptop from within emacs:
M-x slime-connect
localhost
4005
C-x C-f /ssh:remotehost:project/test.lisp
You'll have to setup TRAMP for this to work.
You should also make sure that you have a sensible ssh setup (if you want to work remotely).
Add this to /etc/ssh/ssh_config. It will speed up handshakes for many ssh connections.
Host remotehost
ControlMaster auto
ControlPath /tmp/%r#%h:%p
However if you just want to have things running on your local machine everything is much easier. You can reconnect with SLIME and use M-x slime-list-threads to stop jobs you started earlier in the lisp image.
Related
In ABCL, during development I sometimes get runaway functions. I want to be able to stop execution and return to top level LISP without killing the LISP/JVM process (in my emacs shell) and losing my current LISP environment.
I've tried various control keys (e.g., Control-C, Control-D,...) but at best end up killing LISP or the JVM.
;;; How to stop this function and return to LISP interactive
;;; without killing lisp...?
(defun runaway ()
(let ((result nil))
(dotimes (count 10 result)
(sleep 2)
(print count))))
C-c C-cTerminate batch job (Y/N)? n
n
Process inferior-lisp exited abnormally with code 130
Try using Emacs with Slime instead, because Slime does not kill the process but interrupt the thread and enters the debugger if you press C-c C-c.
You should probably add an executable script abcl.sh somewhere in your PATH, as follows:
#!/bin/sh
exec java -jar .../abcl/abcl-bin-1.5.0/abcl.jar
You have to replace ... with your own path to abcl.jar.
Then, from Emacs, you should be able to start it.
Do C-u M-x slime to force the slime command to prompt for an executable, and give abcl.sh to it. It should start the process and connect to it using the Slime protocol.
I'm trying to learn Common Lisp, and found a simple webserver sample:
#!/usr/local/bin/sbcl --script
;;; The following lines added by ql:add-to-init-file:
#-quicklisp
(let ((quicklisp-init (merge-pathnames "quicklisp/setup.lisp"
(user-homedir-pathname))))
(when (probe-file quicklisp-init)
(load quicklisp-init)))
(ql:quickload "cl-who")
(ql:quickload "hunchentoot")
(ql:quickload "parenscript")
(defpackage :vote
(:use :cl :cl-who :hunchentoot :parenscript))
(in-package :vote)
(hunchentoot:start (make-instance 'hunchentoot:easy-acceptor :port 8080))
(hunchentoot:define-easy-handler (say-yo :uri "/yo") (name)
(setf (hunchentoot:content-type*) "text/plain")
(format nil "Hey~#[ ~A~]!" name))
I'm running it with --script so I can iterate over the code and keep testing it.
The problem is - the script finishes right after launching the server, so I cannot test it.
How could I make the program keep running until I CTRL+D/CTRL+C it?
I could use something like loop and sleep, but it would be too cumbersome - ie, an active wait.
If you're willing to use Ctrl-D, you can use --load instead of --script to load your file. After the file is loaded, you get dropped into a REPL, from which you can use Ctrl-D to quit.
While that may be workable, it might also make sense to consider a timer with a default parameter that can be overridden on the command line, so that the system shuts down after some expiration time. Otherwise, you could inadvertently leave a web server running.
I'm trying to terminate Flymake process before leaving closing the buffer it operates on, albeit unsuccessfully. Below is what I've tried:
(defun haxe-kill-network-process ()
"Kill connection to Haxe compiler server and Flymake process in this buffer"
(when (equal major-mode 'haxe-mode)
(let ((proc (get-process haxe-compiler-process))
(fly-proc (get-buffer-process (buffer-name))))
(when proc
(delete-process proc)
(haxe-log 3 "Disconnecting from HaXe compiler server")
(flymake-mode -1)
(delete-process fly-proc)
(haxe-log 3 "Flymake process killed")))))
(add-hook 'kill-buffer-hook #'haxe-kill-network-process)
I get this output:
Disconnecting from Haxe compiler server
switched OFF Flymake mode for
buffer StripArray.hx due to fatal status CFGERR, warning
Configuration error has occurred while running (haxe --connect
127.0.0.1:1257 --cwd /home/wvxvw/projects/wafer/src
-swf /home/wvxvw/projects/wafer/bin/wunderwafer.swf -cp /home/wvxvw/projects/wafer/src
-swf-header 800:600:31 -swf-version 10 com.wunderwafer.map.StripArray)
Flymake process killed
But it isn't killed by haxe-kill-network-process - it still prompts me for terminating it when I attempt to kill the buffer running the process.
We'd need more information to figure out what happens exactly, but here are some thoughts:
you might like to try and set-process-query-on-exit-flag to avoid the prompt.
always prefer buffers over buffer names (i.e. use (current-buffer) rather than (buffer-name).
you say "it isn't killed" but your code seems to indicate there are various processes involved. So which process isn't killed? What's the exact prompt you get? You might also like to use M-x list-processes to se the runing processes.
Several questions, including this one, discuss aspects relating to ssh connections from within Emacs. I haven't found an answer to my question though: How can I ssh into a remote machine from within Emacs?
I do not wish to edit a file on the remote machine from within Emacs. I am aware of M-x shell which opens a shell on my local machine and I am aware of using TRAMP to edit a file over ssh on the remote machine. However, neither of these relate to this question.
(Instead of voting to close, maybe migrate the question to another site.)
Edit: Related discussion here.
Firstly, I am unaware of a native elisp ssh client (and do not imagine there is a great deal of motivation for writing one), so you will certainly need to interact with an external ssh client process.
As you wish to use ssh interactively, the ssh process requires a terminal on the local side of the connection.
The question therefore becomes: Does Emacs implement a terminal to which an ssh process can be attached?
The answer is: yes -- term.el provides a robust terminal implementation, through which ssh can be run directly, without the requirement for a shell.
If you run M-x term RET you will be prompted for a program. (It defaults to a shell, but that is certainly not the only type of process you can run.)
For reasons unknown, the interactive term (and ansi-term) functions do not support passing arguments to the specified program, which renders them less useful if you wished to run something like ssh user#host. You could instead specify a script which handled the arguments, but we can manage that in elisp as well:
The term function is actually a simple wrapper which calls make-term to start the program and then sets the appropriate modes. As make-term does accept program arguments, it is quite straightforward to copy-and-modify the definition of term to suit your own purposes.
Here is a very simple implementation:
(defun my-ssh (user host port)
"Connect to a remote host by SSH."
(interactive "sUser: \nsHost: \nsPort (default 22): ")
(let* ((port (if (equal port "") "22" port))
(switches (list host "-l" user "-p" port)))
(set-buffer (apply 'make-term "ssh" "ssh" nil switches))
(term-mode)
(term-char-mode)
(switch-to-buffer "*ssh*")))
or perhaps this is preferable:
(defun my-ssh (args)
"Connect to a remote host by SSH."
(interactive "sssh ")
(let ((switches (split-string-and-unquote args)))
(set-buffer (apply 'make-term "ssh" "ssh" nil switches))
(term-mode)
(term-char-mode)
(switch-to-buffer "*ssh*")))
Obviously there is scope for improvements, but I think that's fairly useful as-is.
You should ensure that you are familiar with the quirks of term-mode. See:
M-: (info "(emacs) Terminal emulator") RET
M-: (info "(emacs) Terminal Mode") RET
C-hf term-mode RET
It turns out, there is what you want:
(setq rlogin-program "ssh")
(setq rlogin-process-connection-type t)
and then M-x rlogin RET <myhost> RET will do that.
Maybe ssh.el is what you are looking for. The ssh command provides a single-step way to create remote shells in Emacs via ssh, including specifying the user name in a natural way, and enabling tramp directory tracking if desired.
I'm not sure I understand. Open up M-x ansi-term and run ssh user#host there?
I often use ido for auto-completion and tramp to access remote server via ssh. My .emacs includes the following lines:
(require 'tramp)
(setq tramp-default-method "ssh")
(ido-mode 1)
(setq ido-enable-flex-matching t)
(setq ido-everywhere t)
I want to disable Ido completion, when i'm browsing contents of remote server. Note that variable ido-enable-tramp-completion has nothing to do with my problem. Consider line /root#site.com#1234:/var/www/file.txt. I need Ido not to deduct the part after the colon (remote file path), i don't care about the part before the colon. I use ssh, and Ido makes Emacs lag for a few seconds every time i run ido-find-file, and when ssh timeout is over, Tramp tries to reconnect, asks me for a password and so on. This behavior is undesirable.
Emacs version - 24.0.94.1
Edit (20.03.12): After contact with Ido author I tried to change the ido-file-name-all-completions-1 to the following:
(defun ido-file-name-all-completions-1 (dir)
(cond
((ido-nonreadable-directory-p dir) '())
;; do not check (ido-directory-too-big-p dir) here.
;; Caller must have done that if necessary.
((and ido-enable-tramp-completion
(or (fboundp 'tramp-completion-mode-p)
(require 'tramp nil t))
(string-match "\\`/[^/]+[:#]\\'" dir))
;; TRAMP RELATED CODE DELETED
nil)
(t
(file-name-all-completions "" dir))))
No success. I then changed regex to
"\\`/[^/]+[:#]"
and it worked - Ido was disabled, when minibuffer contained that match. However as Ido couldn't see files on a remote server, it started calling ido-make-merged-file-list to search for files in other directories every time i enter something. This made working with Ido on remote servers even more pain.
I also tried setting up variables ido-slow-ftp-hosts and ido-slow-ftp-host-regexps to /root#site.com#1234, didn't help.
If you enter C-x C-f again you temporally disable ido-find and fall back to the default find-file.
For more information C-h f ido-find-file RET
To do this every time ido found a colon, I guess you have to write your own function for that.