I'm trying to do something way above my head but here's the gist.
- When you press F5 in C or Python some compiling options show up on the minibuffer, those change depending on the major mode you're in
- After selecting one, another function is called that opens eshell, executes the command and switches back to the original window once it detects the process is done
The following works on both C and Python, I'm not good with elisp at all so I kept iterating versions using deepseek, I'd like to know if there's no better way of implementing something like that.
(defvar my/compile-options
'((c-mode
("C with user input" . "make run")
)
(python-mode
("Python with user input" . "python3 -u REPLACE")
)))
(defun my/compile-choice ()
"Prompt for a compilation command and execute it in eshell."
(interactive)
(let (applicable-options)
(dolist (entry my/compile-options)
(when (derived-mode-p (car entry))
(setq applicable-options (append applicable-options (cdr entry)))))
(if (not applicable-options)
(message "No compilation options for current mode")
(let* ((choice (completing-read
"Compile option: "
applicable-options
nil t))
(command (cdr (assoc choice applicable-options))))
(my/run-in-eshell command)))))
(defun my/run-in-eshell (command-str)
"Run COMMAND-STR in eshell, replacing REPLACE with the current filename."
(interactive)
(let ((buf (get-buffer "*eshell*")))
(when buf
(when-let ((win (get-buffer-window buf)))
(delete-window win))
(kill-buffer buf)))
(let ((filename (buffer-file-name)))
(unless filename
(error "Buffer is not visiting a file"))
(eshell)
(switch-to-buffer eshell-buffer-name)
(goto-char (point-max))
(insert (replace-regexp-in-string[Expand Post]
"REPLACE"
(shell-quote-argument filename)
command-str))
(eshell-send-input))
(set-process-sentinel
(get-buffer-process (current-buffer))
(lambda (process _event)
(when (memq (process-status process) '(exit signal))
(previous-window-any-frame)))))
(global-set-key (kbd "<f5>") 'my/compile-choice)
A few notes:
- I need eshell because it needs to work on both linux and windows
- I could only manage to detect when a program terminates inside eshell using process-sentinel
- i delete the existing eshell buffer before initiating because i was having issues sending new commands to the existing shell
- My C program has a simple makefile that runs it (./main)
- In my init.el I have a section to limit the height of the eshell and forces it to be displayed always at the bottom of the current frame
- The way I'm sending the file name (like on python) is really stupid, but it works