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.
Related
I'm playing around with notebooks in emacs. My current setup is EIN (emacs-ipython-notebook) for interactive support, and jupytext for converting .ipynb files to .py, which is useful for diffs and code reviews. Right now I have to run a jupytext shell command to do the sync, but I would like to do this automatically on save, similarly to how jupytext supports this out of the box if you're using Jupyter. I tried the following
(defun sync-jupytext ()
"Sync linked files via jupytext."
(shell-command-to-string (format "jupytext --sync %s" buffer-file-name)))
(add-hook 'after-save-hook #'sync-jupytext)
Unfortunately this doesn't work as buffer-file-name seems to be nil once the ein mode is activated. (It works if I don't C-c C-o to start interactive mode though.) My e-lisp isn't good enough to figure out what variable or code to write instead to get the file name. Can someone help with this?
Ein uses polymode to support multiple major modes in a buffer, and as a result the working buffer isn't associated with the notebook file directly.
The notebook path, which should work in place of buffer-file-name, can be accessed via (ein:$notebook-notebook-name (ein:get-notebook)).
I think for syncing with jupytext you could add an advice around ein:notebook-save-notebook-success to sync the notebook (there might be a cleaner way using the ein:events-on mechanism, but I'm not sure how).
(defun my#sync-jupytext (orig-fn notebook &rest args)
(apply orig-fn notebook args)
(message "[jupytext] %s"
(shell-command-to-string
(format "jupytext --sync %s"
(expand-file-name (ein:$notebook-notebook-name notebook))))))
(advice-add 'ein:notebook-save-notebook-success :around #'my#sync-jupytext)
Did not test this. But maybe the:
(buffer-name)
command might work and you could construct the missing file name:
(concat (buffer-name) ".ipynb")
In emacs there is the RAM buffer and a matching disk file. It goes back to the old timey days where crashes were frequent and they wanted a disk backup.
I have some elisp that runs an external 'npm' command.
(defun npm-mode-npm-run ()
"Run the 'npm run' command on a project script."
(interactive)
(let ((command
(completing-read
"Run command: " (npm-mode--get-project-scripts))))
(message "Running npm script: %s" command)
(switch-to-buffer npm-mode--buffer-name command)
(erase-buffer)
(ansi-term (getenv "SHELL") "npm-mode-npm-run")
(comint-send-string "*npm-mode-npm-run*" (format "npm run-script %s\n" command))))
While it does the job, when execution completes the user is left in a buffer that must be killed, and that requires additional confirmation to kill the process.
What I would like is once the program exits, I could press the 'q' key to do all of that, leaving the user in their original buffer.
Is their a good example of how to do this best for modern emacs that I could refer to, or any other specific docs that may be helpful?
Many thanks in advance!
As #jpkotta said, compile is a good option. You can bury the buffer easily, send a TERM signal to the underlying process, etc. Also, you get for free error parsing (syntax coloring + the ability to jump to the offending line) for many languages.
Here is an example of how I use it (in this case to do a quick run of any script I am editing):
(defun juanleon/execute-buffer ()
(interactive)
(let ((compile-command nil))
(compile buffer-file-name)))
Easy to modify to adapt to your code. The let is for avoid adding stuff to compile history (since I use compile a lot for regular compilation, and history is useful).
In my .emacs, It contains the following two parts of codes.
I am debugging two programs together, one is server, and the other is client.
Everytime switching the debuged program, it is necessary to modify the .erlang for switching the code:add_paths statements and reopening the emacs. (In server and client programs, 3 modules are same, if not switching, the module conflict.
Because reopening emacs is much time-costing ( many files have to be reopened), is it possible for make two .erlang file effective with reopening emacs.
(erlang-shell)
(add-hook 'erlang-mode-hook
(lambda ()
(setq inferior-erlang-machine-options '("-name" "emacs"))
;(setq inferior-erlang-machine-options '("-name" "emacs""-mnesia dir"
"/Users/yuchen/Documents
/Project/mnesia_db") )
(set (make-local-variable 'compile-command) (format "make -f %s"
(get-closest-pathname)))
(imenu-add-to-menubar "imenu")))
You just need to finish your erlang session (switch to *erlang* buffer, enter q(). and press ENTER), edit ~/.erlang and start erlang again with erlang-shell
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.
Is there a way to modify/tell dired to copy files asynchronously? If you mark multiple files in dired and then use 'C' to copy them, emacs locks up until every file is copied. I instead want this copy to be started, and for me to continue editing as it goes on in the background. Is there a way to get this behaviour?
EDIT: Actually, C calls 'dired-do-copy' in dired-aux, not in dired itself. Sorry for any confusion.
I think emacs is mostly limited to a single thread - so this may not be directly possible through standard dired commands such as 'C' copy.
However, there is a dired command "dired-do-shell-command" which calls out to a shell to do the work in the background. If you select the files you want to copy and then use key '!' (this runs dired-do-shell-command) then type 'cp ? [destination]' (possibly can use 'copy' if you are on windows). I haven't tested this - so see help on "dired-do-shell-command" for full details.
See also the Emacs function dired-do-async-shell-command.
For an even more generic solution see https://github.com/jwiegley/emacs-async with which you also can evaluate arbitrary Emacs Lisp code through call to a separate Emacs process (which of course incurs a bit of extra latency). More specifically regard file operations see the file dired-async.el in this repo.
Also note that there is work on threading in Emacs under the working name Concurrent Emacs but it's not there yet. See http://www.emacswiki.org/emacs/ConcurrentEmacs for details.
I found this answer quite helpful: https://emacs.stackexchange.com/a/13802/10761. Reading that answer shows that you can make it so that dired will copy with the scp method instead of the ssh method (the latter initially encodes the file with gzip and that can be quite slow). The scp method will only copy with the scp program when the file is larger than tramp-copy-size-limit (which is 10240 by default). Using this scp method in conjunction with dired-async-mode is very nice, as it will not only copy quickly with scp, but it will also do it asynchronously and out of your way.
Also, I think this is useful: https://oremacs.com/2016/02/24/dired-rsync/. It provides this snippet of code to use rsync to copy files in dired:
;;;###autoload
(defun ora-dired-rsync (dest)
(interactive
(list
(expand-file-name
(read-file-name
"Rsync to:"
(dired-dwim-target-directory)))))
;; store all selected files into "files" list
(let ((files (dired-get-marked-files
nil current-prefix-arg))
;; the rsync command
(tmtxt/rsync-command
"rsync -arvz --progress "))
;; add all selected file names as arguments
;; to the rsync command
(dolist (file files)
(setq tmtxt/rsync-command
(concat tmtxt/rsync-command
(shell-quote-argument file)
" ")))
;; append the destination
(setq tmtxt/rsync-command
(concat tmtxt/rsync-command
(shell-quote-argument dest)))
;; run the async shell command
(async-shell-command tmtxt/rsync-command "*rsync*")
;; finally, switch to that window
(other-window 1)))
(define-key dired-mode-map "Y" 'ora-dired-rsync)