emacs sqlplus disconnected - emacs

I started using sqlplus for emacs. It works fine except one thing - very often I get a message "Buffer ... is not talking to anybody". In a file sqlplus.el there is the following code which verifies (get-buffer-process process-buffer-name). How can I keep alive the sql process?
(defun sqlplus-verify-buffer (connect-string)
(let ((output-buffer-name (sqlplus-get-output-buffer-name connect-string))
(process-buffer-name (sqlplus-get-process-buffer-name connect-string)))
(when (not (get-buffer process-buffer-name))
(sqlplus-shutdown connect-string)
(error "No SQL*Plus session! Use 'M-x sqlplus' to start the SQL*Plus interpreter"))
(unless (get-buffer-process process-buffer-name)
(sqlplus-shutdown connect-string)
(error "Buffer '%s' is not talking to anybody!" output-buffer-name)))
t)

One possible solution is the following
(defadvice sqlplus-verify-buffer (before sqlplus-verify-buffer-and-reconnect activate)
(unless (get-buffer-process (sqlplus-get-process-buffer-name connect-string))
(sqlplus connect-string)))

Related

restart process executed in eshell in emacs

i have started a python process in eshell:
python app.py
i want to restart this with a elisp function, i think comint-quit-subjob when executed with C-c C-\ kills the process but all my attempts to execute comint-quit-subjob have failed
This is what i have so far:
(defun restart-app()
(with-current-buffer "*eshell*"
(interactive)
(comint-quit-subjob)
(eshell-return-to-prompt)
(insert "python app.py")
(eshell-send-input))
)
Hopefully it gives the jist of what i am trying, but it fails. Any ideas?
I would suggest looking for a eshell-ish way of killing a process (I am not a eshell user myself). Comint tries to search something in the buffer. You can workaround that doing something like this (but it is brittle and unelegant):
(defun restart-app()
(with-current-buffer "*eshell*"
(interactive)
(kill-process nil comint-ptyp)
(run-with-timer 0.5 nil
(lambda ()
(with-current-buffer "*eshell*"
(goto-char (point-max))
(insert "python app.py")
(eshell-send-input)))))

Launching shell command in Eshell without prompt interfence

I'm trying to customize my eshell to intercept python to do two things:
Open a new window and run python if no arguments are given (e.g., $ python)
Run the command "per usual" if arguments are given (e.g., $ python foobar.py)
So far I have something like this
(defun eshell/python (&rest cmd-args)
(if (not cmd-args)
(progn (run-python "python")
(select-window (split-window-below))
(switch-to-buffer "*Python*")
(balance-windows)
nil)
(message "Use '*python' to call python directly")))
I've tried replacing (message ...) with a few different things:
Based on the ouput of eshell-parse-command "python test.py" I tried
(progn (eshell-trap-errors
(eshell-named-command "python" cmd-args)))
but it hits a recursion limit.
Since *python test.py does what I want, I then tried
(progn (eshell-trap-errors
(eshell-named-command (concat "*" "python") cmd-args)))
but that puts the python process in the background and interrupts stdout with the output of my eshell-prompt-function.
Finally, I've fiddled with shell-command but I can't get it to write to the eshell buffer. In particular,
(progn (eshell-trap-errors
(shell-command (mapconcat (lambda(x) x) cmd-args " ")
(get-buffer "*eshell*") (get-buffer "*eshell*"))))
gives me a Text is read only message and moves point to start of the eshell buffer.
Is what I'm looking for possible?
Edit 1
Running without eshell/python defined, I've instead tried to avoid alias problems:
(defun eshell/gvr (&rest cmd-args)
(if (not cmd-args)
(progn (run-python "python")
(select-window (split-window-below))
(switch-to-buffer "*Python*")
(balance-windows)
nil)
(progn (eshell-trap-errors
(eshell-named-command "python" cmd-args)))))
If test.py is
print "Hello World"
x = raw_input("What should I repeat? ")
print x
running gvr test.py in eshell fails when I reply to the prompt because eshell tries to execute the input instead of handing it to python, but running python test.py goes off without a hitch.
How can I get run my own subprocesses in eshell the same way that they happen by default?

emacs shell-mode follows its default-directory to current-file

When I enter cd c:/dir/to/path in shell mode, shell mode follows its default-directory to c:/dir/to/path and that's good. But while visiting a certain file(c:/another/dir/file.ext), how can I let the existing shell directory to that one without entering cd c:/antoher/dir/file.ext ?
Is there any pre-exisiting function for that in emacs? searched quite a lot but not found unfortunately.
I'm using Emacs 24.2.1 in Win7.
EDIT:
I've written a not-good-looking function like followings. Any proposal/advice will be appreciated(I'm a novice in elisp).
(With prefixed interactive call, it will show shell buffer with current directory. I'm repeatedly thinking there might be something already invented one better than this).
(defun my-shell-with-current-directory (&optional arg)
(interactive "P")
(let* ((sp (get-process "shell"))
(spbuf (and sp (process-buffer sp)))
(dir (if buffer-file-name (file-name-directory buffer-file-name) default-directory)))
(if (and arg sp spbuf dir)
(progn
(comint-simple-send sp (concat "cd /d " dir))
(display-buffer spbuf)
(save-excursion
(set-buffer spbuf)
(cd dir)
)
)
(progn
(shell)
(comint-simple-send sp "setlocal enableextensions")
)
)
)
)
You may set default-directory using setq at any time.
You may add that code as a hook onto find-file-hooks.
Also you may advice find-file command with the setting wished.
So far just my thoughts...

Update multi-term buffer name based on PWD

If I use konsole or other terminal, the terminal tag name can change based on PWD. But in multi-term, the buffer name is *terminal<number>*. This is not very nice. Because when I switch between them, the name is not very informative. So I want to rename it based on PWD.
I find that the Enter key is bind to term-send-raw, so I write a function
(defadvice term-send-raw (around rename-term-name activate)
(progn
(rename-buffer
(concat "⇒ "
(shell-command-to-string "pwd | xargs basename | tr -d '\n'")
(format-time-string " [%M ∞ %S]")))
ad-do-it))
But the problem is pwd command return the PWD of the terminal buffer, while it is not the PWD of the SHELL in that terminal.
The PWD of the terminal buffer is set by defcustom multi-term-default-dir. And it does not change when the PWD change in the SHELL.
(defcustom multi-term-default-dir "~/"
"The default directory for terms if current directory doesn't exist."
:type 'string
:group 'multi-term)
How can I get the PWD of the SHELL in the terminal?
Regards.
AFAIK there is no easy way to retrieve information from a running process.
But if you want to get the current directory you could:
ask the shell to print it
parse and trace the command-line for functions like cd, pushd, popd…
poll /proc/PID/cwd
The first method is described in the header of term.el (M-xfind-libraryRETtermRET).
And now, thank you for your question, you gave me the opportunity to do this:
(defadvice term-send-input (after update-current-directory)
(let* ((pid (process-id (get-buffer-process (current-buffer))))
(cwd (file-truename (format "/proc/%d/cwd" pid))))
(cd cwd)))
(ad-activate 'term-send-input)
It's a naive implementation of the third method and it doesn't work if the user uses su or ssh. However, I don't know if it's possible withouth using the first or the second method.
In your case, you can just replace the cd command with whatever you want.
Building off of Daimrod's answer for polling /proc/PID/cwd, I found a way get around the problem that Reed pointed out where the advice doesn't pick up the updated CWD immediately and you have to hit Enter twice.
If you move the CWD update code to its own function and use run-at-time to call it from the advice at a later time, it will pick up the updated CWD correctly. Unfortunately I don't know enough about Emacs' scheduling to explain why this works (any enlightenment would be appreciated).
Here's my code based on Daimrod's. Note I advised term-send-input for line-mode and term-send-return for char-mode. I tested this using multi-term on Emacs 24.3.1:
(defadvice term-send-input (after update-current-directory)
(run-at-time "0.1 sec" nil 'term-update-dir)
)
(ad-activate 'term-send-input)
(defadvice term-send-return (after update-current-directory)
(run-at-time "0.1 sec" nil 'term-update-dir)
)
(ad-activate 'term-send-return)
(defun term-update-dir ()
(let* ((pid (process-id (get-buffer-process (current-buffer))))
(cwd (file-truename (format "/proc/%d/cwd" pid))))
(unless (equal (file-name-as-directory cwd) default-directory)
(message (concat "Switching dir to " cwd))
(cd cwd)))
)
Most terminals get their window name from the command echo -en. In zsh you can put this in your ~/.zshenv
precmd() { echo -en "\e]0;`basename ${PWD}`\a" }
and that will get the basename of your PWD environment variable. Ideally multi-term would do something similar and put it in multi-term-buffer-name, which is the variable which holds its buffer name.
Yes, this is not a complete solution. I'm hoping for one too!
Try this:
(defun open-or-jump-to-multi-term ()
(interactive)
(if (string-prefix-p "*terminal<" (buffer-name))
(delete-window)
(progn
(setq bufname (concat "*terminal<" (directory-file-name (file-name-directory (buffer-file-name))) ">"))
(if (get-buffer-process bufname)
(switch-to-buffer-other-window bufname)
(progn
(split-window-right)
(other-window 1)
(multi-term)
(rename-buffer bufname)
)
)))
)
(global-set-key (kbd "C-`") 'open-or-jump-to-multi-term)

Running 'lein swank' (calling clojure server) with elisp

As is asked and answered here. I could use 'lein swank' to run clojure on Aquamacs.
I need to automate running 'lein swank', before running slime/clojure.
Q : Is there a way to this automatically? I mean how can I run the command 'lein swank' automatically when slime/clojure (M-x slime-connect) is called.
Q : If I have to come up with elisp code to run 'lein swank', how can I do that?
Added
Based on Jürgen Hötzel's answer, I modified the elisp as follows.
(defun lein-swank ()
(interactive)
(let ((default-directory (locate-dominating-file default-directory "/Users/smcho/bin/leiningen")))
(when (not default-directory)
(error "Not in a Leiningen project."))
;; you can customize slime-port using .dir-locals.el
(let ((proc (start-process "lein-swank" nil "/Users/smcho/bin/leiningen/bin/lein" "swank" (number-to-string 4005))))
(when proc
(process-put proc :output nil)
(set-process-sentinel proc (lambda (proc event)
(message "%s%s: `%S'"
(process-get proc :output)
proc (replace-regexp-in-string "\n" "" event))))
(set-process-filter proc
(lambda (proc output)
;; record last line of output until connected (possible error message)
(process-put proc :output (concat (process-get proc :output) output))
(when (string-match "Connection opened on" output)
(slime-connect "localhost" 4005)
;; no need to further process output
(set-process-filter proc nil))))
(message "Starting swank server...")))))
But, I got this error.
No project.clj found in this directory. lein-swank: `"exited abnormally with code 1"'.
What I found was that I should change pwd to ~/bin/leiningen to run 'lein swank'. Just put lein binary inside the PATH string doesn't make it run.
I made a gist for this job:
http://gist.github.com/419364
Just use the interactive command "M-x lein-swank", which will spawn the command in the current directory and connect to it.
I made several improvements to lein-swank:
lein-swank-command is now customizable: You can use Leiningen, if its bin directory is not part of your PATH environment.
Added directory as interactive argument: If project.clj can not be found in a dominating location of your current directory, you can specify a location.