/ python-el-expansions.el
python-el-expansions.el
 1  ;;; python-el-expansions.el --- Python-specific expansions for expand-region  -*- lexical-binding: t; -*-
 2  
 3  ;; Copyright (C) 2012-2023  Free Software Foundation, Inc
 4  
 5  ;; Authors: Ivan Andrus, Felix Geller, @edmccard
 6  ;; Based on js-mode-expansions by: Magnar Sveen <magnars@gmail.com>
 7  ;; Keywords: marking region python
 8  
 9  ;; This program is free software; you can redistribute it and/or modify
10  ;; it under the terms of the GNU General Public License as published by
11  ;; the Free Software Foundation, either version 3 of the License, or
12  ;; (at your option) any later version.
13  
14  ;; This program is distributed in the hope that it will be useful,
15  ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16  ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  ;; GNU General Public License for more details.
18  
19  ;; You should have received a copy of the GNU General Public License
20  ;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  
22  ;;; Commentary:
23  
24  ;; For python.el included with GNU Emacs
25  ;;  - Mark functionality taken from python.el:
26  ;;    - `python-mark-block'
27  ;;  - Additions implemented here:
28  ;;    - `er/mark-python-statement'
29  ;;    - `er/mark-inside-python-string'
30  ;;    - `er/mark-outside-python-string'
31  ;;  - Supports multi-line strings
32  
33  ;; There is no need for a er/mark-python-defun since
34  ;; er/mark-python-block will mark it
35  
36  ;; Feel free to contribute any other expansions for Python at
37  ;;
38  ;;     https://github.com/magnars/expand-region.el
39  
40  ;;; Code:
41  
42  (require 'expand-region-core)
43  (require 'python)
44  
45  (declare-function python-beginning-of-string "python-mode")
46  
47  (defvar er--python-string-delimiter "'\"")
48  
49  (defun er/mark-python-statement ()
50    "Marks one Python statement, eg. x = 3"
51    (interactive)
52    (python-nav-end-of-statement)
53    (set-mark (point))
54    (python-nav-beginning-of-statement))
55  
56  (defun er/mark-outside-python-string ()
57    "Marks region outside a (possibly multi-line) Python string"
58    (interactive)
59    (python-beginning-of-string)
60    (set-mark (point))
61    (forward-sexp)
62    (exchange-point-and-mark))
63  
64  (defun er/mark-inside-python-string ()
65    "Marks region inside a (possibly multi-line) Python string"
66    (interactive)
67    (when (eq 'string (syntax-ppss-context (syntax-ppss)))
68      (python-beginning-of-string)
69      (let ((string-beginning (point)))
70        (forward-sexp)
71        (skip-chars-backward er--python-string-delimiter)
72        (set-mark (point))
73        (goto-char string-beginning)
74        (skip-chars-forward er--python-string-delimiter))))
75  
76  (defun er/add-python-mode-expansions ()
77    "Adds Python-specific expansions for buffers in python-mode"
78    (let ((try-expand-list-additions '(er/mark-python-statement
79                                       er/mark-inside-python-string
80                                       er/mark-outside-python-string
81                                       python-mark-block)))
82      (set (make-local-variable 'expand-region-skip-whitespace) nil)
83      (set (make-local-variable 'er/try-expand-list)
84           (remove 'er/mark-inside-quotes
85                   (remove 'er/mark-outside-quotes
86                           (append er/try-expand-list try-expand-list-additions))))))
87  
88  (er/enable-mode-expansions 'python-mode #'er/add-python-mode-expansions)
89  
90  (provide 'python-el-expansions)
91  
92  ;; python-el-expansions.el ends here