8

Brand new emacs user here.

I want to have the ability of opening a terminal with current file path from emacs, like what the open terminal here package does in sublime text 2.

By terminal, I mean a separate external terminal emulator running bash or zsh, like gnome-terminal, not the emulated shells inside emacs, like M-x shell M-x eshell, which I can't appreciate for now.

I googled but had nothing found... It seems that emacs guys really enjoy living in emacs.

stsquad
  • 4,626
  • 28
  • 45
Ply_py
  • 83
  • 1
  • 4
  • Have you tried `M-x` `ansi-term`? It's much better than `shell`. I use it and it works really well. Or do you mean a new graphical terminal (like opening a `gnome-terminal`)? – PythonNut Jan 23 '15 at 05:37
  • @PythonNut I've just tried it, it even couldn't handle the tab completion... So I still prefer a new terminal window. Ahhh, I've just tried `M-! gnome-terminal`, it works. I'm wondering why `M-! bash` couldn't do it. – Ply_py Jan 23 '15 at 05:51
  • @Ply_py I think you need to tell **terminal emulator** and **shell**. `bash` is a shell, `M-! bash` surely won't do what you want. Please find out what terminal emulator you're using first. – kuanyui Jan 23 '15 at 06:41
  • @kuanyui Ahh, I just searched these two words... and found the answers [here](http://askubuntu.com/questions/111144/are-terminal-and-shell-the-same). Clearly I mixed up the notions of shell and terminal(emulator). Thanks, I'll edit the question. – Ply_py Jan 23 '15 at 08:10
  • shell and ansi-term definitely do handle tab completion, at least with bash. I use shell every day. – wdkrnls Jan 23 '15 at 14:43
  • @Ply_py the one pitfall of `ansi-term` is the ease of which you can configure it to death. Try `ansi-term` in an `emacs -Q` session. It works pretty well, even for me with my crazy [shell config](https://github.com/PythonNut/zsh-config). – PythonNut Jan 23 '15 at 17:29

7 Answers7

7

Another try that disowns the process so your terminal will survive even after emacs is killed.

(defun run-gnome-terminal-here ()
  (interactive "@")
  (shell-command (concat "konsole --workdir"
            (file-name-directory (or load-file-name buffer-file-name)) 
              " > /dev/null 2>&1 & disown") nil nil))
PythonNut
  • 10,243
  • 2
  • 29
  • 75
  • Is there a way to tie the spawned terminal to the lifetime of the emacs process? – Greg Nisbet Aug 12 '17 at 23:52
  • This doesn't work (emacs freezes until the terminal exits) if your terminal generates any debug messages when loading. To fix, swap the order of `2>&1` and `>/dev/null` (so that `>/dev/null` comes first). – Mark Aug 14 '17 at 13:06
  • When I try this, Emacs doesn't even let me call the function. After evaluation, the mini buffer says `gnome-terminal-here` but when entering `gnome-terminal-here`, it says `[No match]`. – UTF-8 Sep 17 '17 at 23:14
  • @UTF-8 That's because the function wasn't declared as an interactive command. See my edit. – Gilles 'SO- stop being evil' Sep 18 '17 at 22:26
2

The other answers didn't work for me. This code does:

(defun open-gnome-terminal ()
  (interactive)
  (shell-command "gnome-terminal"))
UTF-8
  • 885
  • 6
  • 22
2

You can use the external package terminal-here. This does only one thing, but does it well; exactly what you requested. And works for me on multiple OS.

InHarmsWay
  • 1,309
  • 7
  • 8
2

What terminal emulator are you using? Take KDE's Konsole as example, just write a function:

(defun open-konsole ()
  (interactive)
  (call-process "konsole" nil 0 nil "--workdir" default-directory))

The args from 5st place are konsole's argument. See your prefered terminal simulator's man page.

M-x open-konsole will open a new konsole process and use current default-directory (pwd in ELisp) as working directory.

kuanyui
  • 1,020
  • 6
  • 16
  • One can open new tab if konsole is already running with `(call-process "konsole" nil 0 nil "--new-tab" "--workdir" default-directory)`. Also `(call-process "wmctrl" nil 0 nil "-a" "\" – Konsole\"")` to activate its window. – Adobe Jan 23 '15 at 18:36
0

Most of the time I use shell-mode. So I heavily use shell-here. But when I need external terminal. I use urxvt-client with tmux using this:

  • Create file named 'term-here' in /usr/local/bin/ containing
urxvtc -e bash -c "tmux -q has-session && exec tmux attach-session -d || exec tmux new-session -n$USER -s$USER@$HOSTNAME"
  • Create new function in emacs
(defun term-here ()
  (interactive)
  (start-process "" nil "term-here"))
  • Bind to your favorite key

This will open urxvt-client (with tmux) in your current directory. I bind it in dired-mode-map.

(use-package dired
  :ensure nil
  :ensure-system-package urxvt
  :bind ((:map dired-mode-map
           ("," . term-here))))

I choose urxvt-client because it is fast and simple. Don't forget to run your urxvt-daemon at startup.

azzamsa
  • 634
  • 7
  • 16
0

Building on terminal-here as proposed before, I created a small function that determines depending on the system and desktop environment the program to run. It can be useful if you like changing desktop, or keep your .emacs synchronized between several computers. Note that I didn't tested the windows/darwin/gnome/... shell code, only KDE is tested for now.

;; ##########################################################
;; ### Open terminal
;; ##########################################################

;; Define a function to recognize the desktop environment easily
;; You shouldn't need to touch this function
(defun get-desktop-environment ()
  (interactive)
  (let (
    ;; Create new variable with DE name
    (de_env (getenv "XDG_CURRENT_DESKTOP"))
    ;; Make sure search is case insensitive
    (case-fold-search t))
    (cond ((eq system-type 'darwin)
       "darwin")
      ((memq system-type '(windows-nt ms-dos cygwin))
       "windows")
      ((string-match ".*kde.*" de_env)
       "kde")
      ((string-match ".*gnome.*" de_env)
       "gnome")
      ((string-match ".*unity.*" de_env)
       "unity")
      ((string-match ".*xfce.*" de_env)
       "xfce")
      ((string-match ".*lxde.*" de_env)
       "lxde")
      ((string-match ".*mate.*" de_env)
       "mate")
      ((string-match ".*cinnamon.*" de_env)
       "cinnamon")
      (t "unknown"))))

;; You can edit this function if you want to change the default command for a specific desktop
(defun get-terminal (path)
  (alist-get (get-desktop-environment)
         '(("darwin" . ("open" "-a" "Terminal.app" "."))
           ("windows" . ("cmd.exe" "/C" "start" "cmd.exe"))
           ("kde" . ("konsole" "--workdir" "."))
           ("gnome" . ("gnome-terminal" "--working-directory=."))
           ("xfce" . ("xfce4-terminal" "--working-directory=.")))
         '("x-terminal-emulator") nil 'equal))

(use-package terminal-here
  :ensure t
  :bind (("<f6>" . terminal-here-launch))
  :config
  (setq terminal-here-terminal-command #'get-terminal))
tobiasBora
  • 405
  • 2
  • 12
0

This worked perfectly fine for me: (delete-window (async-shell-command "gnome-terminal")). Swap out your terminal command.

scribe
  • 930
  • 4
  • 15