How can one quickly browse through lots of files in Emacs? - emacs

is there a way to quickly browse through lots of files in Emacs (24.3)? More specifically:
Let's assume an Emacs frame is split into two windows. Suppose focus is in the left window that has an open 'dired' buffer with lots of text files (or code). I would like to go up and down the list of files (e.g. with cursor keys), while at the same time the current file is shown in the right window. Even better the file is only viewed and closed once I move in the dired buffer to the next file. This would be very useful especially together with some 'omit' mode.
Can this be done in 'dired'? I also coudn't find this functionality in dired-x or in sunrise-commander. Is it possible?
The best candidates I tried already (and why they not solve the problem):
'v' which shows the current file, but also moves the attention
'C-o' which shows the current file, but after moving up or down, I have to press C-o again, also it generates lots of buffers
Thanks a lot for your help!

A simple and generic (while not optimum) solution could be via the C-x () mechanism.
First open the two panes in Emacs, with - say - top one being dired.
Press o to open the first file in the 2nd pane.
Then you can start the repetition mechanism:
do C-x ( to start recording a macro
do C-x k and return to close the buffer
do o again to go back to dired
do down key to go to next file
do o to open next file in bottom pane
do C-x ) to end the macro
From that point (being in bottom pane, dired in top pane), doing a mere
C-x e (and then only e if there is no other operation in between)
will automatically
close bottom pane file, go to top pane, down to next file, open it in bottom pane
There is maybe a more specific way to do that, but knowing the macro mechanism is anyway very helpful in Emacs.

Here's how I do this with view-mode:
(add-hook 'view-mode-hook
(lambda()
(define-key view-mode-map (kbd "n") 'dired-view-next)
(define-key view-mode-map (kbd "p") 'dired-view-prev)))
(defun dired-view-next ()
"Move to next dired line and view ."
(interactive)
(quit-window)
(dired-next-line 1)
(dired-view-file))
(defun dired-view-prev ()
"Move to next dired line and view ."
(interactive)
(quit-window)
(dired-next-line -1)
(dired-view-file))
UPD:
This one has two panes:
(defun dired-view-next-pane ()
(interactive)
(other-window 1)
(if view-mode
(kill-buffer))
(other-window -1)
(dired-next-line 1)
(view-file-other-window
(dired-get-file-for-visit))
(other-window -1))

Thanks a lot for all those answers. Summarizing I created the following solution (extending the answer of "abo-abo"):
;; little modification to dired-mode that let's you browse through lots of files
(add-hook 'dired-mode-hook
(lambda()
(define-key dired-mode-map (kbd "C-o") 'dired-view-current) ; was dired-display-file
(define-key dired-mode-map (kbd "n") 'dired-view-next) ; was dired-next-line
(define-key dired-mode-map (kbd "p") 'dired-view-previous))) ; was dired-previous-line
(defun dired-view-next ()
"Move down one line and view the current file in another window."
(interactive)
(dired-next-line)
(dired-view-current))
(defun dired-view-previous ()
"Move up one line and view the current file in another window."
(interactive)
(dired-previous-line)
(dired-view-current))
(defun dired-view-current ()
"View the current file in another window (possibly newly created)."
(interactive)
(if (not (window-parent))
(split-window)) ; create a new window if necessary
(let ((file (dired-get-file-for-visit))
(dbuffer (current-buffer)))
(other-window 1) ; switch to the other window
(unless (equal dbuffer (current-buffer)) ; don't kill the dired buffer
(if (or view-mode (equal major-mode 'dired-mode)) ; only if in view- or dired-mode
(kill-buffer))) ; ... kill it
(let ((filebuffer (get-file-buffer file)))
(if filebuffer ; does a buffer already look at the file
(switch-to-buffer filebuffer) ; simply switch
(view-file file)) ; ... view it
(other-window -1)))) ; give the attention back to the dired buffer
Three keys are changed:
C-o to view the current item in another window (possibly create one).
n to view the next item in another window.
p to view the previous item in another window.
This can be used in a dired buffer. Note that only dired-mode buffers and view-mode buffers get killed while moving up and down. If a file is shown that another buffer is already visiting (not in view-mode), that buffer is shown as well, but not killed when moving to the next. Another subtlety is the case when the passively shown buffer is the dired buffer used for going through the list (this can easily happen, when going inside a folder with RET). To handle this case, we first check whether we are trying to kill the initial dired buffer.

Load Icicles.
Define this command:
(defun my-find-file ()
"Like `icicle-find-file', but alt action views file temporarily.
Alternate action keys such as `C-S-down' visit the candidate file in
`view-mode' and kill the buffer of the last such viewed candidate."
(interactive)
(let ((icicle-candidate-alt-action-fn
(lambda (file)
(when (and my-last-viewed
(get-file-buffer my-last-viewed))
(kill-buffer (get-file-buffer my-last-viewed)))
(setq my-last-viewed (abbreviate-file-name file))
(view-file file)
(select-frame-set-input-focus
(window-frame (active-minibuffer-window))))))
(icicle-find-file-of-content)))
(defvar my-last-viewed nil
"Last file viewed by alternate action of `my-find-file'.")
Then you can:
Use M-x my-find-file (or bind it to a key - e.g., C-x C-f).
Optionally type part of a file name, to limit the matching names.
Optionally use down or up to cycle among file names.
Use C-S-down to visit the next file in order.
Repeat #4 to see other files in order.
Repeat #2 or #3 to see other sets of files.
End with RET to choose a file to visit or C-g to cancel.
Each file buffer you visited with C-S-down was killed when you
viewed the next one. You can also mix in C-down or C-RET to
also visit files whose buffers you do not want to kill
automatically. (Change view-file to find-file if you don't
want to visit in view-mode, which is read-only.)
[By default, the alternate action for icicle-find-file is
icicle-alt-act-fn-for-type, which prompts you for a file-
appropriate action to use on the particular candidate chosen for
the action. Command my-find-file just substitutes a different
alternate action function (for all candidates you choose).]
See also this thread from help-gnu-emacs#gnu.org. It is pretty much the same question as yours, I think. My replies there were pretty much the same as my reply here, but there are also replies from others that might help you as well.

Try
M-x speedbar
That might appeal to you

Another view-mode solution on top of ag-mode lists. I couldn't find a question for ag-mode, maybe this helps someone generalize a ffap-preview for any mode.
(defun directory-ag-results ()
(save-excursion
(goto-char (point-min))
(search-forward "\"")
(setq a (point))
(search-forward "\"")
(setq b (- (point) 1))
(buffer-substring-no-properties a b)))
(defun search-item-path ()
(let ((dir (directory-ag-results))
(file-parts (split-string (substring-no-properties (thing-at-point 'filename)) ":")))
(concat dir (nth 0 file-parts))))
(defun search-item-line ()
(let ((file-parts (split-string (substring-no-properties (thing-at-point 'filename)) ":")))
(- (string-to-number (nth 1 file-parts)) 1)))
(defun view-current ()
"Quickly view the current file in another window."
(if (not (window-parent))
(split-window)) ; create a new window if necessary
(let ((file (search-item-path))
(line (search-item-line))
(dbuffer (current-buffer)))
(other-window 1) ; switch to the other window
(unless (equal dbuffer (current-buffer)) ; don't kill the dired buffer
(if (or view-mode (equal major-mode 'dired-mode)) ; only if in view- or dired-mode
(kill-buffer))) ; ... kill it
(let ((filebuffer (get-file-buffer file)))
(if filebuffer ; does a buffer already look at the file
(switch-to-buffer filebuffer) ; simply switch
(progn
(view-file file) ; ... view it
(goto-char (point-min))
(next-line line)))
(other-window -1))))
(defun next-view-current ()
(interactive)
(next-line)
(view-current))
(defun previous-view-current ()
(interactive)
(previous-line)
(view-current))
(define-key ag-mode-map (kbd "M-p") 'previous-view-current)
(define-key ag-mode-map (kbd "M-n") 'next-view-current)
This is the one thing I think Sublime does better than Emacs. Blasphemy, I know! I like the "q to exit" feel of view-mode, rather than timer-based solutions, and like scrolling around a previewed file. This snippet navigates to the line number found in the search results, optimizing for browsing speed.
Note about the code: I tried polyfilling vc-root-dir from Emacs 25, but it doesn't really make sense for ag-mode since ag-mode's buffer is outside the repo you're searching in. I ended up pulling the root dir from the top of the "ag search" buffer.
Early stages. Improvements welcome.
Demo
Edit: It works for ag-mode, not dired. Demo gif.
Credits: abo-abo, user2979331

In the interest of keeping StackOverflow up to date, the package peep-dired does everything posted in the other answers, and I’m sure there are other packages as well. You don’t have to maintain copypasted or home-rolled lisp for this job.

Related

Show all open buffers in Emacs

In emacs, is there an M-x command or key combo to render all current open buffers into different windows?
For clarity, let's suppose I have four open buffers, and I am only seeing one currently being displayed, and I would like in one step to show each buffer in one quadrant.
I recommend ibuffer. M-x ibuffer is probably what you want. Here's my ibuffer configuration:
;; *Messages* is so annoying. Also, I really like ibuffer
(require 'ibuf-ext)
(add-to-list 'ibuffer-never-show-predicates "^\\*Messages")
(add-to-list 'ibuffer-never-show-predicates "^\\*Completions")
(global-set-key (kbd "C-b") 'ibuffer)
(kill-buffer "*scratch*")
('ibuffer)
(switch-to-buffer "*Ibuffer*")
You will be able to start with the following code if there is not an already-known way to do it:
(defun buffer-in-window-list ()
(let (buffers)
(walk-windows (lambda (window) (push (window-buffer window) buffers)) t t)
buffers))
(defun display-all-buffers ()
(interactive)
(let (buffers-in-window (buffer-in-window-list))
(dolist (buffer (buffer-list))
(when (and (not (string-match "\\`[[:space:]]*\\*" (buffer-name buffer)))
(not (memq buffer buffers-in-window)))
(set-window-buffer (split-window (get-largest-window)) buffer)))
(balance-windows)))
The display-all-buffers command opens a new window for each buffer that is not currently displayed anywhere (including other frames). For usability, it ignores buffers whose names start with * (optionally, prefixed with whitespace characters) because they are usually for internal use only.
Note that Emacs does not allow a user to make too small a window. So, when there are too many buffers to display, the command will display as many buffers as possible in order of most recent display or selection and signal an error.

switch buffer settings using python-mode in emacs?

I have been using emacs for a while but not so familiar with lisp programming. Its been just couple of days I started coding Python on emacs. I found python-mode to be quite useful and I want to explore it further. I found a few emacs lips functions on internet, tewaked them a bit to make the interface userfriendly. I am trying to achieve following actions
I usually start emacs with 2 vertical windows, one with python source and other is a shell. I should be able to do following using keyboard bindings
switch between buffers (working)
execute a region (working)
but replaces the source buffer with shell buffer. I want to execute selected region in original shell buffer.
execute a line (working)
but same issue as above. when i pres say , the line should be executed in python shell without replacing any buffers. so copy the line, switch to python shell, execute line, switch back to python source buffer.
I am not able to achieve switching action above. Following is my code from my init.el file
(defun goto-python-shell ()
"Go to the python command window (start it if needed)"
(interactive)
(setq current-python-script-buffer (current-buffer))
(if (boundp 'current-python-shell-buffer)
(switch-to-buffer-other-window current-python-shell-buffer)
(py-shell))
(end-of-buffer)
)
(defun goto-python-source ()
"switch back to source window"
(interactive)
(setq current-python-shell-buffer (current-buffer))
(switch-to-buffer-other-window current-python-script-buffer)
)
(defun py-execute-statement-and-step ()
"select a statement, submit as a region and then step forward"
(interactive)
(beginning-of-line 1)
(let ((beg (point)))
(py-next-statement 1)
; if last statement.
(if (= (point) beg) (end-of-buffer ))
; (switch-to-buffer-other-window current-python-shell-buffer)
(py-execute-region beg (point))
(switch-to-buffer-other-window current-python-script-buffer)
)
)
; some key bindings
(define-key python-mode-map (quote [f9]) 'py-execute-statement-and-step)
;(define-key python-mode-map (quote [f10]) `py-execute-region)
;py-shell-switch-buffers-on-execute
(define-key python-mode-map (quote [f10]) `py-shell-switch-buffers-on-execute)
(define-key python-mode-map (quote [f11]) `py-execute-buffer)
(define-key python-mode-map (quote [f12]) `goto-python-shell)
(define-key py-shell-map (quote [f12]) `goto-python-source)
Please advice.
Also since i am new to python-mode, can someone share nice initializations for using python-mode similar to above?
thanks much for your help.
Regards,
AJ
You should take a look at the first answer to this question and customize the py-shell-switch-buffers-on-execute variable.
This way you won't need all your custom functions to make python-mode work like you want (i.e. keeping the source buffer active)
I think that you are trying to reinvent what is available in Emacs 24 (at least with evaluation stuff). Try Emacs 24. When you are editing a Python source code, you can press C-c C-c to evaluate a buffer and press C-c C-r to evaluate a region. You don't have to explicitly start a Python shell.
I don't think that there is a direct support for evaluate a line and step. You can achieve it by the keystrokes C-SPC C-n C-c C-r. Your focus will remain in the source code and there is no need to switch explicitly between the source code and the shell.
FWIW, I have been using Emacs 24 for a reasonable amount of time on a daily basis and I haven't encountered any stability issues.
following changes are working like a charm. f9 does line by line execute and f10 does region based execution. curser remains in the script window after i disabled py-shell-switch-buffers-on-execute.
(defun py-execute-statement-and-step ()
"select a statement, submit as a region and then step forward"
(interactive)
(beginning-of-line 1)
(let ((beg (point)))
(py-next-statement 1)
; if last statement.
(if (= (point) beg) (end-of-buffer ))
(py-execute-region beg (point))
(next-line)
)
)
(custom-set-variables
'(py-shell-switch-buffers-on-execute nil))
(define-key python-mode-map (quote [f9]) 'py-execute-statement-and-step)
(define-key python-mode-map (quote [f10]) `py-execute-region)

In Emacs, how can I open a buffer/file in "ibuffer/dired mode" in another frame?

When I am working with multiple frames, I want to decide in which frame Emacs should open files/buffers.
You can't do that out of the box.
There are find-buffer-other-frame and the like but they open a new frame.
What you can do is write your own function like this:
(defun find-file-in-frame ()
(interactive)
(call-interactively 'select-frame-by-name)
(call-interactively 'find-file))
This switches frame and then asks for the file, if you want to do it otherwise you have to do more work.
Edit: Here the version that asks in the current frame and opens the file in the other window:
(defun find-file-in-frame (noselect)
(interactive "P")
(let ((current-frame (selected-frame))
(frame (completing-read "Frame: " (make-frame-names-alist)))
(buffer (save-window-excursion
(call-interactively 'find-file))))
(select-frame-set-input-focus (assoc-default frame
(make-frame-names-alist)
nil current-frame))
(switch-to-buffer buffer)
(when noselect
(select-frame-set-input-focus current-frame))))
If you are just referring to find-file, then I would suggest that with the combination of windmove and framemove, switching to the frame in which you wish to open the file is so trivial and fast that you probably don't need anything fancier.
OTOH if you want to be able to select a frame whenever a file is to be opened by any means, this obviously doesn't apply.
Not sure what you're really asking. But as to opening a file from Dired in another frame, just use C-o or M-mouse-2 in Dired+. Those are bound to these commands, in case you do not want to load Dired+ for some reason:
(defun diredp-find-file-other-frame () ; Bound to `C-o'
"In Dired, visit this file or directory in another frame."
(interactive)
(find-file-other-frame (file-name-sans-versions (dired-get-filename nil t) t)))
(defun diredp-mouse-find-file-other-frame (event) ; Bound to `M-mouse-2'
"In Dired, visit file or directory clicked on in another frame."
(interactive "e")
(let ((pop-up-frames t)) (dired-mouse-find-file-other-window event)))

How can I switch focus after buffer split in emacs?

I would like that after splitting the window (C-x 3 or C-x 2) to be able to automatically get to cursor in the new opened buffer (the other than the current). How can I achieve this behavior ?
You can switch between buffers with C-x o. As to do that automatically I don't think there is an existing command for that.
You can do it like this:
(global-set-key "\C-x2" (lambda () (interactive)(split-window-vertically) (other-window 1)))
(global-set-key "\C-x3" (lambda () (interactive)(split-window-horizontally) (other-window 1)))
In Emacs 24.3.1 it works if you change the argument 1 for 0.
!!!DO NOT USE THIS ANSWER!!! -- as pointed out in the comments, advising split-window can lead to undesired side-effects.
I recommend Bozhidar Batsov's answer instead.
Put the following in your .emacs file:
(defadvice split-window (after move-point-to-new-window activate)
"Moves the point to the newly created window after splitting."
(other-window 1))
As well as splitting the frame manually with C-x 2 or C-x 3, buffers are also automatically "popped-up" some times. These are also not selected/active by default.
This can be fixed by changing the function used to split a window. It's set to split-window-sensibly by default, but you can set it to your own function that calls split-window-sensibly and then selects the buffer.
Unfortunately, though, this has the side-effect of selecting the *Completions* buffer when you hit TAB in the minibuffer. So, it's worth checking to see if the minibuffer is active and not switching in this case. I'd bet there are other such undesirable scenarios as well. I'll try to update this post as and when I find them.
;; after splitting a frame automatically, switch to the new window (unless we
;; were in the minibuffer)
(setq split-window-preferred-function 'my/split-window-func)
(defun my/split-window-func (&optional window)
(let ((new-window (split-window-sensibly window)))
(if (not (active-minibuffer-window))
(select-window new-window))))
(Works with Emacs 24.5.1.)
My thought of when you would want to follow the window after a split-window was when it had the same buffer like in the following code:
(defun split-window--select-window (orig-func &rest args)
"Switch to the other window after a `split-window'"
(let ((cur-window (selected-window))
(new-window (apply orig-func args)))
(when (equal (window-buffer cur-window) (window-buffer new-window))
(select-window new-window))
new-window))
(advice-add 'split-window :around #'split-window--select-window)
Simple
C-x o will help you switch to the "other" buffer.

How to open multiple terminals?

In Emacs, I often find myself in a situation where I need to jump back and forth between various source files to various terminals. However, I feel like I do not have a good way to do this efficiently and it's clumsy that you can only open one shell in Emacs (shell, eshell, or term).
Moreover, I need an efficient way of juggle between multiple terminals and source files.
How can I achieve this?
You can have as many terminals and shells open at once as you want. Just use M-x rename-buffer to change the name of an existing *term* or *shell* buffer, and the next time you do M-x term or M-x shell, a brand new buffer will be created. In the case of M-x shell, a prefix argument will cause you to be prompted for the name of the new shell buffer, as offby1 noted.
A few years ago I had a job where I had to regularly log in to various production servers named "host01.foo.com", "host02.foo.com", etc. I wrote a little function like this one to make it easier to manage them all:
(defun ssh-to-host (num)
(interactive "P")
(let* ((buffer-name (format "*host%02d*" num))
(buffer (get-buffer buffer-name)))
(if buffer
(switch-to-buffer buffer)
(term "/bin/bash")
(term-send-string
(get-buffer-process (rename-buffer buffer-name))
(format "ssh host%02d.foo.com\r" num)))))
Then I bound this command to (say) s-h (super H), enabling me to just type M-5 s-h. If I didn't already have a buffer named *host05*, it would start a new terminal emulator buffer, rename it to *host05*, and ssh me into host05.foo.com. If buffer *host05* already existed, it would simply switch me to it. Quite handy!
You can certainly have multiple interactive shells open. Try typing C-u M-x shell RET RET.
Try using MultiTerm to open multiple shells.
You can use Emacs Lisp Screen, which emulates GNU Screen and provides easy key bindings to jump to and between a number of different shells.
I use many methods for incorporating my terminal life into Emacs:
elscreen.el is a life saver, if you have a complicated window layout like gdb or have simply become overwhelmed with clutter you just open a new screen. In your case you could dedicate one screen to terminals.
multi-term.el makes managing terminals a bit easier.
shell-pop.el, a great tool for quick terminal access. shell-pop lets you assign a key to opening and closing a specific shell buffer window, if you've used drop-down terminals like tilda you know how incredibly handy this can be:
Here's and example of my shell-pop configuration, I use the key C-t to pop up an eshell:
(require 'shell-pop)
(shell-pop-set-internal-mode "eshell") ; Or "ansi-term" if you prefer
(shell-pop-set-window-height 60) ; Give shell buffer 60% of window
;; If you use "ansi-term" and want to use C-t
;; (defvar ansi-term-after-hook nil)
;; (add-hook 'ansi-term-after-hook
;; '(lambda ()
;; (define-key term-raw-map (kbd "C-t") 'shell-pop)))
;; (defadvice ansi-term (after ansi-term-after-advice (org))
;; (run-hooks 'ansi-term-after-hook))
;; (ad-activate 'ansi-term)
(global-set-key (kbd "C-t") 'shell-pop)
I usually do an an M-x server-start and then use emacsclient --no-wait to open files. I've aliased that to e with some embellishments so that it's a little more convenient.
I do all my work in a single terminal and just "throw" the files I want to edit into Emacs using e. Inside Emacs, I juggle around using iswitchb and it works just fine. YMMV.
I regularly used 10 or so shells in my old workplace. The secret is you have to rename additional shell buffers. I did this automatically though in my .emacs, creating and naming the shells logically (I had projnameRun and projnameBuild for every project). Worked really well together with anything, making it very easy to refind the right shell (you use the end of the project name combined with either r or b for run/build).
Instead of having several terminal windows in emacs, I spawn a different xterm whenever I need a new terminal. This of course is bearable because I use a very lightweight terminal emulator (urxvt) which starts in under 0.2s.
Then I use my window manager to switch between them and emacs frames. A configurable window manager will have plenty of options to tune to switch between windows (extremely) efficiently. Inside emacs, I use windmove and ido-mode, and have bound to C-tab a function that switches to the last buffer (because I use C-x b in that fashion a lot).
So um, not sure how useful it is to you since it's quite different from your use pattern, but this is what works for me.
I had exactly the same problem some years ago, and found nothing that satisfied me; so I wrote my own "toggle shell" function. It toggles between the current frame or window configuration and a system shell buffer. It can also put the shell into a dedicated frame, and inject a pushd to the current buffer directory.
This is an excerpt from my .emacs:
(defvar --toggle-shell-last-window-conf nil "The last window configuration.")
(defvar --toggle-shell-last-buf nil "The last buffer object in case there's no last window configuration.")
(defvar --toggle-shell-last-frame nil "The frame that was selected when opening a shell buffer.")
(defun --toggle-shell-have-conf ()
(window-configuration-p --toggle-shell-last-window-conf))
(defun --toggle-shell-store-last-conf ()
(setq --toggle-shell-last-buf (current-buffer)
--toggle-shell-last-frame (selected-frame)
--toggle-shell-last-window-conf (current-window-configuration)))
(defun --toggle-shell-restore-last-conf ()
(if (--toggle-shell-have-conf)
(progn (raise-frame --toggle-shell-last-frame)
(set-window-configuration --toggle-shell-last-window-conf))
(let ((bufnam (if (bufferp --toggle-shell-last-buf)
(buffer-name --toggle-shell-last-buf) --toggle-shell-last-buf)))
(if bufnam
(if (get-buffer bufnam) (switch-to-buffer bufnam t)
(message "%s: buffer not available" bufnam))))))
(defun --toggle-shell (&optional display inject-cd)
"Toggles between current buffers and a system shell buffer. With prefix-arg
close the shell.
When DISPLAY is 'vertical splits the shell as vertical window; when 'frame uses
a dedicated frame (default: single window). When INJECT-CD executes a `pushd'
to the working directory of the buffer from which you toggled the shell."
(interactive)
(let* ((shell-buf (get-buffer "*shell*"))
(shell-window ; non-nil when currently displayed
(if shell-buf (get-buffer-window shell-buf t)))
(shell-frame
(if shell-window (window-frame shell-window)))
(in-shell (eq (current-buffer) shell-buf))
(vertical (string= display 'vertical))
(popup-frame (or (string= display 'frame)
(and inject-cd (not (bufferp shell-buf)))
(and (framep shell-frame)
(not (eq shell-frame (selected-frame)))))))
;; With prefix-arg close shell, restore windows. Otherwise (no prefix-arg)
;; toggle shell window; restore windows when called twice in a row, or the
;; current buffer is the shell buffer (`in-shell').
(if current-prefix-arg
(if (bufferp shell-buf)
(progn (message "Exiting shell '%s'" (buffer-name shell-buf))
(kill-buffer shell-buf)
(if in-shell (--toggle-shell-restore-last-conf)))
(error "No shell buffer to kill."))
;; If already in shell-buffer toggle back to stored frame-configuration.
(if (and in-shell (not inject-cd))
(progn
(--toggle-shell-restore-last-conf)
;; Recurse to reopen the shell-buffer in a dedicated frame, or
;; close the dedicated frame and reopen the buffer in a window.
(if (and popup-frame (eq shell-frame (selected-frame)))
(--toggle-shell 'frame inject-cd)
(when (and popup-frame shell-frame)
(delete-frame shell-frame)
(--toggle-shell nil inject-cd))))
;; Not in shell buffer. Warp to it or create new one.
(unless in-shell
(--toggle-shell-store-last-conf))
(if popup-frame
(progn (switch-to-buffer-other-frame (or shell-buf "*shell*"))
(raise-frame
(or shell-frame (window-frame (get-buffer-window "*shell*" t)))))
(if (> (count-windows) 1)
(delete-other-windows)))
;; Finally `cd' into the working directory the current buffer.
(let ((new-shell (not (bufferp shell-buf)))
(new-dir ; `default-directory' of `--toggle-shell-last-buf'
(if --toggle-shell-last-buf
(buffer-local-value 'default-directory --toggle-shell-last-buf))))
;; Open shell, move point to end-of-buffer. The new shell-buffer's
;; `default-directory' will be that of the buffer the shell was
;; launched from.
(when vertical
(if (> (count-windows) 1)
(delete-other-windows))
(split-window-vertically) (other-window 1))
(funcall 'shell)
(when new-shell
(message "New shell %s (%s)" (buffer-name (current-buffer)) new-dir)
(if inject-cd (sit-for 2))) ; wait for prompt
(goto-char (point-max))
;; If on a command-prompt insert and launch a "cd" command (assume no
;; job is running).
(when (and inject-cd new-dir)
(save-excursion
(backward-line-nomark) (end-of-line)
(unless (setq inject-cd (re-search-forward comint-prompt-regexp (point-max) t))
(error "Cannot `pushd', shell is busy")))
(when (and inject-cd)
(let* ((cmd (format
"pushd '%s' %s" (comint-quote-filename new-dir)
(if (buffer-file-name --toggle-shell-last-buf)
(format "# '%s'" (file-name-directory (buffer-file-name --toggle-shell-last-buf)))
""))))
;; `shell-process-cd' set new `default-directory' and set
;; `shell-last-dir' to old. (If the pushd command is
;; successful, a dirs is performed as well; >nul discards this
;; output.)
(shell-process-cd new-dir)
(insert cmd)
(comint-send-input)
(message "%s: cd '%s'" (buffer-name --toggle-shell-last-buf) new-dir))
)
)
)
)
)
)
)
--toggle-shell is the function that does the trick. I bind it to F12:
;; F12 toggle between shell buffer and current window configuration
;; SHIFT-F12 like before, but let shell buffer appear in a dedicated frame
;; ALT-F12 inject a pushd to change to directory of current buffer
;; CTRL-F12 `shell-command'
(global-set-key [(f12)] '--toggle-shell)
(global-set-key [(shift f12)] '(lambda()(interactive)(--toggle-shell 'frame)))
(global-set-key [(meta f12)] '(lambda()(interactive)(--toggle-shell nil t)))
(global-set-key [(meta f10)] '(lambda()(interactive)(--toggle-shell nil t)))
(global-set-key [(control f12)] 'shell-command) ; alias M-!
This is a significant bunch of code to be posted here. But it shall work well.
Semi related - you can quickly run a shell command on selected file with
M+shift+!
It saves a lot of time for smaller commands chmod etc
And maybe my quick pop-up shell also might help you. A quick pop-up shell for emacs
Ecb + eshell will be what you want exactly!
I use vi, but hope this helps. I can open as many terminals as I want by (eg. in Ubuntu 16.04):
ctrl + alt + t
I usually open 2 terminals, and move (position) one terminal to the right by:
ctrl + super + right-arrow
and move the other terminal to the left by:
ctrl + super + left-arrow
so that I have a divided screen by 2 terminals.