I have the following Common Lisp code:
(defun micro-read-eval-print ()
(format t "Micro > ")
(let ((form (read-line)))))
When I run it, I get the following:
CL-USER> (micro-read-eval-print)
(m-quote a)
Micro > NIL
Note that I typed in "(m-quote a)", while the Lisp interpreter output "Micro > NIL".
Now, I would have expected these events to happen in the reverse order. I would have expected "Micro > " to have been printed first since the format statement comes first. Why isn't it printed first? And what do I have to do to make sure it is printed first?
Try adding
(defun micro-read-eval-print ()
(format t "Micro > ")
(finish-output)
(let ((form (read-line)))))
I believe you are encountering the buffering of standard io (stdio) which, in C, is commonly bypassed via fflush() in that language.
finish-output appears to be the Common Lisp equivalent of C standard library's fflush.
Related
Editing a Bash script I want to assign a filename to a variable.
E.g. inputfile=foo.txt
With std. settings I can't complete the filename without first inserting a space after the '='.
Is there any solution to this?
First of all, comint-dynamic-complete has been obsolete since Emacs 24.1. The replacement function is completion-at-point.
Now, if you starting looking at what completion-at-point actually does in a shell script buffer, you'll eventually end up in comint anyway. In particular, the function comint--match-partial-filename looks promising for an explanation of the behavior you described.
If I read that correctly, the problem here is that "=" is considered a valid part of a filename, at least on POSIX-like systems (see variable comint-file-name-chars). So, the completion mechanism is trying to complete the filename "inputfile=/..." which it can obviously not find.
If you never use a "=" in your filenames (or you use it so rarely that the working completion outweighs other downsides), you may want to consider doing something like (setq comint-file-name-chars "[]~/A-Za-z0-9+#:_.$#%,{}-") in the shell script mode hook (if you are on a POSIX system; on Windows it would look slightly different).
Hope that helps.
You can use bash-completion assuming your not on windows. It just requires a slight modification to work in sh-mode since it uses a comint function to determine the current completion candidate.
I like this because, in addition to completing filenames there, it also will give you all the nice readline completion like command line switches, etc. Here is an example setup using company, but you could remove the company stuff, since all you really need is to add the modified completion-at-point function.
;; required packages: company bash-completion
(eval-when-compile
(require cl-lib))
;; locally redefine comint-line-beginning-position so bash-completion
;; can work in sh-mode
(defun sh-bash-completion ()
(cl-letf (((symbol-function 'comint-line-beginning-position)
#'(lambda ()
(save-excursion
(sh-beginning-of-command)
(point)))))
(let ((syntax (syntax-ppss)))
(and (not (or (nth 3 syntax)
(nth 4 syntax)))
(bash-completion-dynamic-complete)))))
;; put this in your sh-mode hook
(defun sh-completion-setup ()
;; add capf function
(add-hook 'completion-at-point-functions
'sh-bash-completion nil 'local)
(company-mode)
(make-local-variable 'company-backends)
;; use company completion-at-point
(delq 'company-capf company-backends)
(cl-pushnew 'company-capf company-backends)
(setq-local company-transformers
'(company-sort-by-backend-importance)))
(add-hook 'sh-mode-hook 'sh-completion-setup)
I have a simple elisp interactive function that I use to launch a Clojure repl.
(defun boot-repl ()
(interactive)
(shell-command "boot repl wait &"))
It opens an *Async Shell Command* buffer, and after a while the following text appears :
nREPL server started on port 59795 on host 127.0.0.1 - nrepl://127.0.0.1:59795
Implicit target dir is deprecated, please use
the target task instead. Set BOOT_EMIT_TARGET=no to disable implicit
target dir.
I would like to monitor the output of this command to be able to parse the port ("59795" in this example).
Even just the first line (in the case without warnings) would be alright.
This way I could be able to use another command to connect to the Clojure REPL waiting for me.
I cannot use shell-command-to-string as the command does not return and it blocks emacs forever (boot repl wait is supposed to last for my whole programming session, possibly more).
There may be something easy to do with cider also, but I haven't found it.
So, how do I parse the result of an asynchronous bash command in Elisp ?
Alternatively, how can I set-up Cider to launch this REPL for my and connect to it ?
To answer the question directly, you can definitely parse the output of an asyncronous shell command, using start-process and set-process-filter:
(let ((proc (start-process "find" "find" "find"
(expand-file-name "~") "-name" "*el")))
(set-process-filter proc (lambda (proc line)
(message "process output: %s" line))))
(Docs for filter function)
However, note that line above is not necessarily a line, and may include multiple lines or broken lines. Your filter is called whenever the process or emacs decides to flush some ouput:
...
/home/user/gopath/src/github.com/gongo/json-reformat/test/json-reformat-test.el
/home/user/gopath/src/github.com/gongo/json-reformat/test/test-
process output: helper.el
In your case, this could mean that your port number might be broken into two separate process-filter calls.
To fix this, we can introduce a line-buffering and line-splitting wrapper, which calls your filter for each process output line:
(defun process-filter-line-buffer (real-filter)
(let ((cum-string-sym (gensym "proc-filter-buff"))
(newline (string-to-char "\n"))
(string-indexof (lambda (string char start)
(loop for i from start below (length string)
thereis (and (eq char (aref string i))
i)))))
(set cum-string-sym "")
`(lambda (proc string)
(setf string (concat ,cum-string-sym string))
(let ((start 0) new-start)
(while (setf new-start
(funcall ,string-indexof string ,newline start))
;;does not include newline
(funcall ,real-filter proc (substring string start new-start))
(setf start (1+ new-start)));;past newline
(setf ,cum-string-sym (substring string start))))))
Then, you can safely expect your lines to be whole:
(let* ((test-output "\nREPL server started on port 59795 on host 127.0.0.1 - \nrepl://127.0.0.1:59795 Implicit target dir is deprecated, please use the target task instead. Set BOOT_EMIT_TARGET=no to disable implicit target dir.")
(proc (start-process "echo-test" "echo-test" "echo" test-output)))
(set-process-filter proc (process-filter-line-buffer
(lambda (proc line)
(when (string-match
"REPL server started on port \\([0-9]+\\)"
line)
(let ((port (match-string 1 line)))
;;take whatever action here with PORT
(message "port found: %s" port)))))))
Finally, I'm not familiar with cider but this kind of low-level work probably belongs in an inferior-type mode and has probably already been solved.
shell-command
allows to name optional output- and error-buffers. Than the error should appear inside the latter and not clutter the output any more.
A better answer to the other one I provided is to simply use cider as you suggested:
(progn
(package-refresh-contents)
(package-install 'cider)
(cider-jack-in))
I'm porting a Python script to Racket as a learning experience, and I have this function:
(define (check-status)
(define git [find-executable-path "git"])
(define-values (ckot out in err)
(subprocess #f #f #f git "checkout" "-q" "master"))
(define-values (local lout lin lerr)
(subprocess #f #f #f git "rev-parse" "#"))
(define-values (remote rout rin rerr)
(subprocess #f #f #f git "rev-parse" "#{u}"))
(define-values (merge-base mbout mbin mberr)
(subprocess #f #f #f git "merge-base" "#" "#{u}"))
(display-lines (port->lines mbout))
(define ports '(ckot out in err local lout lin lerr remote rout rin rerr merge-base mbout mbin mberr))
(map (lambda (x)
(cond ((input-port? x) (close-input-port x))
((output-port? x) (close-output-port x)))) ports))
The problem is that it's not very DRY. Since I'm using a Lisp, and Lisp is known for being able to do crazy things, I want to know if there's a way to take all the subprocess code and extract it so I can do something like:
(define (check-status)
(define commands '(
'("checkout" "-q" "master")
'("rev-parse" "#")
'("rev-parse" "#{u}")
'("merge-base" "#" "#{u}"))
(map currently-immaginary-git-command-fn commands))
and end up with a list of the output of each command in the list of commands. How would I do this? Since I'm new to the whole Lisp/Scheme thing, I'm figuring out the syntax as I go and I'm not fully aware of the resources available to me.
First of all, good for you for wanting to come up with a cleaner solution! You're right that there's a more elegant way to do what you've attempted.
To start, using subprocess is almost certainly overkill in your particular use-case. The racket/system module provides a simpler interface that should be sufficient for your needs. Specifically, I'd use the system* function, which executes a single process with the provided arguments, then prints its output to stdout.
Using system*, it's possible to create a very general helper function that can execute a command for a particular executable and returns its output as a string.
(define (execute-command proc-name)
(define proc (find-executable-path proc-name))
(λ (args)
(with-output-to-string
(thunk (apply system* proc args)))))
This function itself returns a new function when it's called. This means that using it to call a Git command would look like this:
((execute-command "git") '("checkout" "-q" "master"))
The reason for this will become apparent shortly.
Actually looking at the implementation of execute-command, we use with-output-to-string to redirect all of the output from the system* call into a string (instead of just printing it to stdout). This is actually just an abbreviation for using parameterize to set the current-output-port parameter, but it's simpler.
With this function, we can implement check-status very easily.
(define (check-status)
(define commands
'(("checkout" "-q" "master")
("rev-parse" "#")
("rev-parse" "#{u}")
("merge-base" "#" "#{u}")))
(map (execute-command "git") commands))
Now the reason for having (execute-command "git") return a new function becomes apparent: we can use that to create a function which will then map over the commands list to produce a new list of strings.
Also, note that the definition of the commands list only uses a single ' at the beginning. The definition you provided would not work, and in fact, the ports list you defined in your original implementation is not what you'd expect. This is because '(...) is not exactly the same as (list ...)—they are different, so be careful when using them.
The problem is here: http://www.spoj.com/problems/TEST/
And my scheme solution is:
(define (main)
(let ((line (read-line)))
(if (or
(eof-object? line)
(string=? line "42"))
(void)
(begin
(display line)
(newline)
(main)))))
(main)
It reports
runtime error (NZEC)
But I don't know why it's wrong.
You should install guile and try your code before you submit. Guile doesn't have read-line available by default. You need to add this as first line:
(use-modules (ice-9 rdelim))
So what happens is that guile post an error and return a non zero value back to the parent process, which in turns indicated the program did not terminate normally. SPOJ will then report is as NZEC.
The guile error looks like this:
sylwester#sylhp ~> guile test.scm
ERROR: Unbound variable: read-line
Whenever you get NZEC you should try to run it locally to find errors.
When using DrScheme with R5RS, there is no error function. I plan to write my own, but can't figure out how to halt the program execution. I tried commands such as:
(halt)
(exit)
(error)
and none worked. How do you halt program execution?
SLIB (the portable Scheme library) has an implementation of ERROR. You might want to either look at that, or use SLIB in your programs.
Other than that, one way to halt the program is simply to raise a different error! Try something like this (thanks to Stephen Houben):
(define (error reason . args)
(display "Error: ")
(display reason)
(for-each (lambda (arg)
(display " ")
(write arg))
args)
(newline)
(scheme-report-environment -1)) ;; we hope that this will signal an error
While this does raise a second (unrelated) error, it will surely halt program execution.
Is there a reason you need to use R5RS? Other language definitions in DrScheme define error and exit. For example, the (module ...) PLT language defines error and exit. Invoking mzscheme from the command line also gives you these definitions.
Note: I have DrScheme 372, which is pretty old. Things shouldn't have changed too much, though.
an ugly solution is to define abort to become a runtime error.
for example any of these should do the trick
(define abort "the program was aborted")
(define abort 123)
(define abort #f)
any call to abort
(abort)
should generate a runtime error, if your lucky even show the string , error code or whatever you care.