Compare commits

..

3 commits

Author SHA1 Message Date
Howard Abrams
b23f15a670 Fix inconsistencies with Demo and Remoting 2025-03-30 10:00:36 -07:00
Howard Abrams
ff16e20067 Fix bug when using SSH in Pud 2025-03-30 10:00:06 -07:00
Howard Abrams
5e9ed1bbd0 Level up on Python programming with elpy 2025-03-30 09:59:35 -07:00
5 changed files with 166 additions and 78 deletions

View file

@ -485,6 +485,9 @@ These interactive functions scroll the “notes” in the other window in anothe
#+END_SRC #+END_SRC
* New Demonstration * New Demonstration
:LOGBOOK:
CLOCK: [2025-03-26 Wed 09:04]--[2025-03-26 Wed 09:29] => 0:25
:END:
Instead of executing a sequence of demonstration steps, demonstrations key on “state”, that is, the active buffer or major-mode, or the heading of an Org file, etc. I described the [[https://howardism.org/Technical/Emacs/demonstrations-part-two.html][guts of writing this code]], but we bind a key to calling =ha-demo-step= with a list of /state matchers/ to functions to call when matched. For instance: Instead of executing a sequence of demonstration steps, demonstrations key on “state”, that is, the active buffer or major-mode, or the heading of an Org file, etc. I described the [[https://howardism.org/Technical/Emacs/demonstrations-part-two.html][guts of writing this code]], but we bind a key to calling =ha-demo-step= with a list of /state matchers/ to functions to call when matched. For instance:
#+BEGIN_SRC emacs-lisp :tangle no :eval no #+BEGIN_SRC emacs-lisp :tangle no :eval no
@ -844,8 +847,8 @@ All options? Should I use Common Lisps =cl-defun= for the keyword parameters?
(switch-to-buffer filename)) (switch-to-buffer filename))
(if image-minor-mode (if image-minor-mode
(goto-char (point-min)) (image-transform-fit-to-window)
(image-transform-fit-to-window)) (goto-char (point-min)))
(ha-demo-set-side-window :size size :modeline modeline (ha-demo-set-side-window :size size :modeline modeline
:cursor cursor) :cursor cursor)
@ -984,18 +987,18 @@ And we can open the shell in a window:
(when command (when command
(sit-for 1) (sit-for 1)
(ha-shell-send command ha-demo-shell-dir)) (ha-shell-send command))
(when (and focus (eq focus 'presentation)) (when (and focus (eq focus 'presentation))
(pop-to-buffer orig-buf)))) (pop-to-buffer orig-buf))))
(defun ha-demo-shell-send (command) (defun ha-demo-shell-send (command)
"Send COMMAND to the currently opened shell, `ha-demo-shell'." "Send COMMAND to the currently opened shell, `ha-demo-shell'."
(ha-shell-send command ha-demo-shell-dir)) (ha-shell-send command))
(defun ha-demo-shell-quit () (defun ha-demo-shell-quit ()
"Close the window associated with a shell." "Close the window associated with a shell."
(ha-shell-send "exit" ha-demo-shell-dir) (ha-shell-send "exit")
(delete-other-windows)) (delete-other-windows))
#+END_SRC #+END_SRC

View file

@ -66,7 +66,7 @@ The Escape key act like ~C-g~ and always go back to normal mode?
;; (global-set-key (kbd "<escape>") 'keyboard-escape-quit) ;; (global-set-key (kbd "<escape>") 'keyboard-escape-quit)
;; Let's connect my major-mode-hydra to a global keybinding: ;; Let's connect my major-mode-hydra to a global keybinding:
(evil-define-key 'normal 'global "," 'major-mode-hydra) (evil-define-key '(normal visual) 'global "," 'major-mode-hydra)
(evil-mode)) (evil-mode))
#+end_src #+end_src

View file

@ -3,6 +3,8 @@
#+date: 2021-11-16 #+date: 2021-11-16
#+tags: emacs python programming #+tags: emacs python programming
import re
A literate programming file for configuring Python. A literate programming file for configuring Python.
#+begin_src emacs-lisp :exports none #+begin_src emacs-lisp :exports none
@ -37,80 +39,111 @@ While Emacs supplies a Python editing environment, well still use =use-packag
(setq python-indent-guess-indent-offset-verbose nil (setq python-indent-guess-indent-offset-verbose nil
flycheck-flake8-maximum-line-length 120) flycheck-flake8-maximum-line-length 120)
:config :config
(when (and (executable-find "ipython") (setq python-shell-interpreter (or (executable-find "ipython") "python"))
(string= python-shell-interpreter "ipython"))
(setq python-shell-interpreter "ipython"))
(flycheck-add-next-checker 'python-pylint 'python-pycompile 'append)) (flycheck-add-next-checker 'python-pylint 'python-pycompile 'append))
#+end_src #+end_src
Note: Install the following checks: ** Keybindings
Instead of memorizing all the Emacs-specific keybindings, we use [[https://github.com/jerrypnz/major-mode-hydra.el][major-mode-hydra]] defined for =python-mode=:
#+BEGIN_SRC emacs-lisp
(use-package major-mode-hydra
:after python
:config
(defvar ha-python-eval-title (font-icons 'mdicon "run" :title "Python Evaluation"))
(defvar ha-python-goto-title (font-icons 'faicon "python" :title "Python Symbol References"))
(defvar ha-python-refactor-title (font-icons 'faicon "recycle" :title "Python Refactoring"))
(pretty-hydra-define python-evaluate (:color blue :quit-key "C-g"
:title ha-python-eval-title)
("Section"
(("f" python-shell-send-defun "Function/class")
("e" python-shell-send-statement "Line")
(";" python-shell-send-string "Expression"))
"Entirety"
(("f" python-shell-send-file "File")
("b" python-shell-send-buffer "Buffer")
("r" elpy-shell-send-region-or-buffer "Region"))))
(pretty-hydra-define python-refactor (:color blue :quit-key "C-g"
:title ha-python-refactor-title)
("Simple"
(("r" iedit-mode "Rename"))
"Imports"
(("A" python-add-import "Add Import")
("a" python-import-symbol-at-point "Import Symbol")
("F" python-fix-imports "Fix Imports")
("S" python-sort-imports "Sort Imports"))))
(pretty-hydra-define python-goto (:color pink :quit-key "C-g"
:title ha-python-goto-title)
("Statements"
(("s" xref-find-apropos "Find Symbol" :color blue)
("j" python-nav-forward-statement "Next")
("k" python-nav-backward-statement "Previous"))
"Functions"
(("F" imenu "Jump Function" :color blue)
("f" python-nav-forward-defun "Forward")
("d" python-nav-backward-defun "Backward")
("e" python-nav-end-of-defun "End of" :color blue))
"Blocks"
(("u" python-nav-up-list "Up" :color blue)
(">" python-nav-forward-block "Forward")
("<" python-nav-backward-block "Backward"))))
(major-mode-hydra-define python-mode (:quit-key "C-g" :color blue)
("Server"
(("S" run-python "Start Server")
("s" python-shell-switch-to-shell "Go to Server"))
"Edit"
(("r" python-refactor/body "Refactor...")
(">" python-indent-shift-left "Shift Left")
("<" python-indent-shift-right "Shift Right"))
"Navigate/Eval"
(("e" python-evaluate/body "Evaluate...")
("g" python-goto/body "Go to..."))
"Docs"
(("d" python-eldoc-at-point "Docs on Symbol")
("D" python-describe-at-point "Describe Symbol")))))
#+end_src
Sections below can add to this with =major-mode-hydra-define+=.
Note: Install the following packages /globally/ for Emacs:
#+begin_src sh #+begin_src sh
pip install flake8 pylint pyright mypy pycompile pip install flake8 flake8-bugbear pylint pyright mypy pycompile black ruff ipython
#+end_src #+end_src
Or better yet, add those to the =requirements-dev.txt= file.
All the above loveliness can be easily accessible with a [[https://github.com/jerrypnz/major-mode-hydra.el][major-mode-hydra]] defined for =emacs-lisp-mode=: But certainly add those to each projects =requirements-dev.txt= file.
#+begin_src emacs-lisp iPython has a feature of [[https://ipython.readthedocs.io/en/stable/config/intro.html#python-configuration-files][loading code on startup]] /per profile/. First, create it with:
(use-package major-mode-hydra
:config
(defvar ha-python-eval-title (font-icons 'mdicon "run" :title "Python Evaluation"))
(defvar ha-python-goto-title (font-icons 'faicon "python" :title "Python Symbol References"))
(pretty-hydra-define python-evaluate (:color blue :quit-key "q" #+BEGIN_SRC sh
:title ha-python-eval-title) ipython profile create
("Section" #+END_SRC
(("f" python-shell-send-defun "Function/Class")
("e" python-shell-send-statement "Line")
(";" python-shell-send-string "Expression"))
"Entirety"
(("F" python-shell-send-file "File")
("B" python-shell-send-buffer "Buffer")
("r" python-shell-send-region "Region"))))
(pretty-hydra-define python-goto (:color blue :quit-key "q" Next, after reading David Vujics [[https://davidvujic.blogspot.com/2025/03/are-we-there-yet.html][Are We There Yet]] essay, I took a look at [[https://github.com/DavidVujic/my-emacs-config?tab=readme-ov-file#python-shell][his Python configuration]], and added the /auto reloading/ feature to the iPython /profile configuration/:
:title ha-python-goto-title)
("Symbols"
(("s" xref-find-apropos "Find Symbol")
("e" python-shell-send-statement "Line")
(";" python-shell-send-string "Expression"))
"Entirety"
(("F" python-shell-send-file "File")
("B" python-shell-send-buffer "Buffer")
("r" python-shell-send-region "Region"))))
(major-mode-hydra-define python-mode (:quit-key "q" :color blue) #+BEGIN_SRC python :tangle ~/.ipython/profile_default/ipython_config.py
("Server" c = get_config() #noqa
(("S" run-python "Start Server")
("s" python-shell-switch-to-shell "Go to Server")) %load_ext autoreload
"Edit" %autoreload 2
(("r" iedit-mode "Rename")
(">" python-indent-shift-left "Shift Left") # c.InteractiveShellApp.extensions = ['autoreload']
("<" python-indent-shift-right "Shift Right")) # c.InteractiveShellApp.exec_lines = ['%autoreload 2']
"Navigate/Eval" #+END_SRC
(("e" python-evaluate/body "Evaluate...")
("g" python-goto/body "Go to..."))
"Docs"
(("d" python-eldoc-at-point "Docs on Symbol")
("D" python-describe-at-point "Describe Symbol")))))
#+end_src
** Virtual Environment ** Virtual Environment
For a local virtual machine, put the following in your =.envrc= file: When you need a particular version of Python, use [[https://github.com/pyenv/pyenv][pyenv]] globally:
#+begin_src conf
layout_python3
#+end_src
That is pretty slick and simple.
The old way, that we still use if you need a particular version of Python, is to install [[https://github.com/pyenv/pyenv][pyenv]] globally:
#+begin_src sh #+begin_src sh
pip install pyenv pip install pyenv
#+end_src #+end_src
And have this in your =.envrc= file: And have this in your =.envrc= file for use with [[file:ha-programming.org::*Virtual Environments with direnv][direnv]]:
#+begin_src conf #+begin_src conf
use python 3.7.1 use python 3.7.1
#+end_src #+end_src
Also, you need the following in your =~/.config/direnv/direnvrc= file (which I have): Also, you need the following in your =~/.config/direnv/direnvrc= file (which I have):
@ -175,7 +208,57 @@ Your project's =.envrc= file would contain something like:
("Misc" ("Misc"
(("t" python-tests/body "Tests...")))))) (("t" python-tests/body "Tests..."))))))
#+end_src #+end_src
** Python Dependencies * Elpy
The [[https://elpy.readthedocs.io/en/latest/introduction.html][Elpy Project]] expands on the =python-mode=.
#+BEGIN_SRC emacs-lisp
(use-package elpy
:ensure t
:init
(elpy-enable))
#+END_SRC
Lets expand our =major-mode-hydra= with some extras:
#+begin_src emacs-lisp
(use-package major-mode-hydra
:after elpy
:config
(pretty-hydra-define python-evaluate (:color blue :quit-key "q"
:title ha-python-eval-title)
("Section"
(("F" elpy-shell-send-defun "Function")
("E" elpy-shell-send-statement "Statement")
(";" python-shell-send-string "Expression"))
"Entirety"
(("B" elpy-shell-send-buffer "Buffer")
("r" elpy-shell-send-region-or-buffer "region"))
"And Step..."
(("f" elpy-shell-send-defun-and-step "Function" :color pink)
("e" elpy-shell-send-statement-and-step "Statement" :color pink))))
(pretty-hydra-define+ python-refactor nil
("Elpy"
(("r" elpy-refactor-rename "Rename")
("i" elpy-refactor-inline "Inline var")
("v" elpy-refactor-extract-variable "To variable")
("f" elpy-refactor-extract-function "To function")
("a" elpy-refactor-mode "All..."))))
(major-mode-hydra-define+ python-mode (:quit-key "q" :color blue)
("Server"
(("s" elpy-shell-switch-to-shell "Go to Server")
("C" elpy-config "Config Elpy"))
"Edit"
(("f" elpy-black-fix-code "Fix/format code"))
"Docs"
(("d" elpy-eldoc-documentation "Describe Symbol")
("D" elpy-doc "Docs Symbol")))))
#+end_src
* LSP Integration of Python
** Dependencies
Each Python project's =requirements-dev.txt= file would reference the [[https://pypi.org/project/python-lsp-server/][python-lsp-server]] (not the /unmaintained/ project, =python-language-server=): Each Python project's =requirements-dev.txt= file would reference the [[https://pypi.org/project/python-lsp-server/][python-lsp-server]] (not the /unmaintained/ project, =python-language-server=):
#+begin_src conf :tangle no #+begin_src conf :tangle no
@ -198,7 +281,7 @@ Each Python project's =requirements-dev.txt= file would reference the [[https://
stestr slowest stestr slowest
# ... # ...
#+end_src #+end_src
*** Pyright ** Pyright
Im using the Microsoft-supported [[https://github.com/Microsoft/pyright][pyright]] package instead. Adding this to my =requirements.txt= files: Im using the Microsoft-supported [[https://github.com/Microsoft/pyright][pyright]] package instead. Adding this to my =requirements.txt= files:
#+begin_src conf :tangle no #+begin_src conf :tangle no
pyright pyright
@ -212,7 +295,7 @@ The [[https://github.com/emacs-lsp/lsp-pyright][pyright package]] works with LSP
:init (when (executable-find "python3") :init (when (executable-find "python3")
(setq lsp-pyright-python-executable-cmd "python3"))) (setq lsp-pyright-python-executable-cmd "python3")))
#+end_src #+end_src
* LSP Integration of Python *** Keybindings
Now that the [[file:ha-programming.org::*Language Server Protocol (LSP) Integration][LSP Integration]] is complete, we can stitch the two projects together, by calling =lsp=. I oscillate between automatically turning on LSP mode with every Python file, but I sometimes run into issues when starting, so I conditionally turn it on. Now that the [[file:ha-programming.org::*Language Server Protocol (LSP) Integration][LSP Integration]] is complete, we can stitch the two projects together, by calling =lsp=. I oscillate between automatically turning on LSP mode with every Python file, but I sometimes run into issues when starting, so I conditionally turn it on.
#+begin_src emacs-lisp #+begin_src emacs-lisp

View file

@ -305,8 +305,8 @@ Now that Emacs can /host/ a Terminal shell, I would like to /programmatically/ s
#+begin_src emacs-lisp #+begin_src emacs-lisp
(defun ha-shell-send (command &optional name) (defun ha-shell-send (command &optional name)
"Send COMMAND to existing shell terminal based on DIRECTORY. "Send COMMAND to existing shell terminal based on DIRECTORY.
If you want to refer to another session, specify the correct NAME. If you want to refer to another session, specify the correct NAME.
This is really useful for scripts and demonstrations." This is really useful for scripts and demonstrations."
(unless name (unless name
(setq name ha-latest-ssh-window-name)) (setq name ha-latest-ssh-window-name))
@ -314,14 +314,16 @@ Now that Emacs can /host/ a Terminal shell, I would like to /programmatically/ s
(pop-to-buffer name) (pop-to-buffer name)
(goto-char (point-max)) (goto-char (point-max))
(cond (cond
((eq major-mode 'vterm-mode) (progn ((eq major-mode 'vterm-mode) (progn
(vterm-send-string command) (vterm-send-string command)
(vterm-send-return))) (vterm-send-return)))
((eq major-mode 'eat-mode) (eat-term-send-string ((eq major-mode 'eat-mode) (eat-term-send-string
ha-eat-terminal (concat command "\n"))) ha-eat-terminal (concat command "\n")))
(t (progn (t (progn
(insert command) (insert command)
(term-send-input)))))) (term-send-input))))))
(ha-shell-send "exit")
#+end_src #+end_src
Let's have a quick way to bugger out of the terminal: Let's have a quick way to bugger out of the terminal:

View file

@ -2,7 +2,7 @@
#+author: Howard X. Abrams #+author: Howard X. Abrams
#+date: 2025-01-18 #+date: 2025-01-18
#+filetags: emacs hamacs #+filetags: emacs hamacs
#+lastmod: [2025-03-03 Mon] #+lastmod: [2025-03-21 Fri]
A literate programming file for a Comint-based MUD client. A literate programming file for a Comint-based MUD client.
@ -263,7 +263,7 @@ Command string to use, given a =world= with a connection type:
(cl-case (aref world 1) (cl-case (aref world 1)
(telnet (append (cons pud-telnet-path pud-cli-arguments) (telnet (append (cons pud-telnet-path pud-cli-arguments)
(list host port))) (list host port)))
(ssh (append (cons pud-cli-filepath-ssh pud-cli-arguments) (ssh (append (cons pud-ssh-path pud-cli-arguments)
(list "-p" port host))) (list "-p" port host)))
(t (error "Unsupported connection type"))))) (t (error "Unsupported connection type")))))
#+END_SRC #+END_SRC