aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/progmodes/python.el
diff options
context:
space:
mode:
authorFabián Ezequiel Gallina2012-07-16 10:13:01 -0300
committerFabián Ezequiel Gallina2012-07-16 10:13:01 -0300
commit032d23ab664d571be03f5661034d1962baa4f5ae (patch)
treeadfd6edbaab5c3edac9297aa30e2d7ce35b804e8 /lisp/progmodes/python.el
parent9328d9aabae2f45f82b59aad5214a3f13ee1b2a1 (diff)
downloademacs-032d23ab664d571be03f5661034d1962baa4f5ae.tar.gz
emacs-032d23ab664d571be03f5661034d1962baa4f5ae.zip
* progmodes/python.el: Enhancements to navigation commands.
(python-nav-backward-sentence) (python-nav-forward-sentence): Remove. (python-nav-backward-statement, python-nav-forward-statement) (python-nav-statement-start, python-nav-statement-end) (python-nav-backward-block, python-nav-forward-block) (python-nav-block-start, python-nav-block-end) (python-nav-forward-sexp-function) (python-info-current-line-comment-p) (python-info-current-line-empty-p): New functions. (python-indent-context): Use `python-nav-statement-start'.
Diffstat (limited to 'lisp/progmodes/python.el')
-rw-r--r--lisp/progmodes/python.el226
1 files changed, 201 insertions, 25 deletions
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index ddedbdb7ddc..fe9faf54046 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -46,11 +46,13 @@
46 46
47;; Movement: `beginning-of-defun' and `end-of-defun' functions are 47;; Movement: `beginning-of-defun' and `end-of-defun' functions are
48;; properly implemented. There are also specialized 48;; properly implemented. There are also specialized
49;; `forward-sentence' and `backward-sentence' replacements 49;; `forward-sentence' and `backward-sentence' replacements called
50;; (`python-nav-forward-sentence', `python-nav-backward-sentence' 50;; `python-nav-forward-block', `python-nav-backward-block'
51;; respectively). Extra functions `python-nav-sentence-start' and 51;; respectively which navigate between beginning of blocks of code.
52;; `python-nav-sentence-end' are included to move to the beginning and 52;; Extra functions `python-nav-forward-statement',
53;; to the end of a sentence while taking care of multiline definitions. 53;; `python-nav-backward-statement', `python-nav-statement-start',
54;; `python-nav-statement-end', `python-nav-block-start' and
55;; `python-nav-block-end' are included but no bound to any key.
54;; `python-nav-jump-to-defun' is provided and allows jumping to a 56;; `python-nav-jump-to-defun' is provided and allows jumping to a
55;; function or class definition quickly in the current buffer. 57;; function or class definition quickly in the current buffer.
56 58
@@ -227,10 +229,10 @@
227 (let ((map (make-sparse-keymap))) 229 (let ((map (make-sparse-keymap)))
228 ;; Movement 230 ;; Movement
229 (substitute-key-definition 'backward-sentence 231 (substitute-key-definition 'backward-sentence
230 'python-nav-backward-sentence 232 'python-nav-backward-block
231 map global-map) 233 map global-map)
232 (substitute-key-definition 'forward-sentence 234 (substitute-key-definition 'forward-sentence
233 'python-nav-forward-sentence 235 'python-nav-forward-block
234 map global-map) 236 map global-map)
235 (define-key map "\C-c\C-j" 'python-nav-jump-to-defun) 237 (define-key map "\C-c\C-j" 'python-nav-jump-to-defun)
236 ;; Indent specific 238 ;; Indent specific
@@ -664,7 +666,7 @@ START is the buffer position where the sexp starts."
664 ((setq start (save-excursion 666 ((setq start (save-excursion
665 (back-to-indentation) 667 (back-to-indentation)
666 (python-util-forward-comment -1) 668 (python-util-forward-comment -1)
667 (python-nav-sentence-start) 669 (python-nav-statement-start)
668 (point-marker))) 670 (point-marker)))
669 'after-line) 671 'after-line)
670 ;; Do not indent 672 ;; Do not indent
@@ -1097,10 +1099,10 @@ Returns nil if point is not in a def or class."
1097 (python-info-ppss-context-type)) 1099 (python-info-ppss-context-type))
1098 (forward-line 1))))))) 1100 (forward-line 1)))))))
1099 1101
1100(defun python-nav-sentence-start () 1102(defun python-nav-statement-start ()
1101 "Move to start of current sentence." 1103 "Move to start of current statement."
1102 (interactive "^") 1104 (interactive "^")
1103 (while (and (not (back-to-indentation)) 1105 (while (and (or (back-to-indentation) t)
1104 (not (bobp)) 1106 (not (bobp))
1105 (when (or 1107 (when (or
1106 (save-excursion 1108 (save-excursion
@@ -1110,8 +1112,8 @@ Returns nil if point is not in a def or class."
1110 (python-info-ppss-context 'paren)) 1112 (python-info-ppss-context 'paren))
1111 (forward-line -1))))) 1113 (forward-line -1)))))
1112 1114
1113(defun python-nav-sentence-end () 1115(defun python-nav-statement-end ()
1114 "Move to end of current sentence." 1116 "Move to end of current statement."
1115 (interactive "^") 1117 (interactive "^")
1116 (while (and (goto-char (line-end-position)) 1118 (while (and (goto-char (line-end-position))
1117 (not (eobp)) 1119 (not (eobp))
@@ -1121,28 +1123,185 @@ Returns nil if point is not in a def or class."
1121 (python-info-ppss-context 'paren)) 1123 (python-info-ppss-context 'paren))
1122 (forward-line 1))))) 1124 (forward-line 1)))))
1123 1125
1124(defun python-nav-backward-sentence (&optional arg) 1126(defun python-nav-backward-statement (&optional arg)
1125 "Move backward to start of sentence. With ARG, do it arg times. 1127 "Move backward to previous statement.
1126See `python-nav-forward-sentence' for more information." 1128With ARG, repeat. See `python-nav-forward-statement'."
1127 (interactive "^p") 1129 (interactive "^p")
1128 (or arg (setq arg 1)) 1130 (or arg (setq arg 1))
1129 (python-nav-forward-sentence (- arg))) 1131 (python-nav-forward-statement (- arg)))
1130 1132
1131(defun python-nav-forward-sentence (&optional arg) 1133(defun python-nav-forward-statement (&optional arg)
1132 "Move forward to next end of sentence. With ARG, repeat. 1134 "Move forward to next statement.
1133With negative argument, move backward repeatedly to start of sentence." 1135With ARG, repeat. With negative argument, move ARG times
1136backward to previous statement."
1134 (interactive "^p") 1137 (interactive "^p")
1135 (or arg (setq arg 1)) 1138 (or arg (setq arg 1))
1136 (while (> arg 0) 1139 (while (> arg 0)
1140 (python-nav-statement-end)
1137 (python-util-forward-comment) 1141 (python-util-forward-comment)
1138 (python-nav-sentence-end) 1142 (python-nav-statement-start)
1139 (forward-line 1)
1140 (setq arg (1- arg))) 1143 (setq arg (1- arg)))
1141 (while (< arg 0) 1144 (while (< arg 0)
1142 (python-nav-sentence-end) 1145 (python-nav-statement-start)
1143 (python-util-forward-comment -1) 1146 (python-util-forward-comment -1)
1144 (python-nav-sentence-start) 1147 (python-nav-statement-start)
1145 (forward-line -1) 1148 (setq arg (1+ arg))))
1149
1150(defun python-nav-block-start ()
1151 "Move to start of current block."
1152 (interactive "^")
1153 (let ((starting-pos (point))
1154 (block-regexp (python-rx
1155 line-start (* whitespace) block-start)))
1156 (if (progn
1157 (python-nav-statement-start)
1158 (looking-at (python-rx block-start)))
1159 (point-marker)
1160 ;; Go to first line beginning a statement
1161 (while (and (not (bobp))
1162 (or (and (python-nav-statement-start) nil)
1163 (python-info-current-line-comment-p)
1164 (python-info-current-line-empty-p)))
1165 (forward-line -1))
1166 (let ((block-matching-indent
1167 (- (current-indentation) python-indent-offset)))
1168 (while
1169 (and (python-nav-backward-block)
1170 (> (current-indentation) block-matching-indent)))
1171 (if (and (looking-at (python-rx block-start))
1172 (= (current-indentation) block-matching-indent))
1173 (point-marker)
1174 (and (goto-char starting-pos) nil))))))
1175
1176(defun python-nav-block-end ()
1177 "Move to end of current block."
1178 (interactive "^")
1179 (when (python-nav-block-start)
1180 (let ((block-indentation (current-indentation)))
1181 (python-nav-statement-end)
1182 (while (and (forward-line 1)
1183 (not (eobp))
1184 (or (and (> (current-indentation) block-indentation)
1185 (or (python-nav-statement-end) t))
1186 (python-info-current-line-comment-p)
1187 (python-info-current-line-empty-p))))
1188 (python-util-forward-comment -1)
1189 (point-marker))))
1190
1191(defun python-nav-backward-block (&optional arg)
1192 "Move backward to previous block of code.
1193With ARG, repeat. See `python-nav-forward-block'."
1194 (interactive "^p")
1195 (or arg (setq arg 1))
1196 (python-nav-forward-block (- arg)))
1197
1198(defun python-nav-forward-block (&optional arg)
1199 "Move forward to next block of code.
1200With ARG, repeat. With negative argument, move ARG times
1201backward to previous block."
1202 (interactive "^p")
1203 (or arg (setq arg 1))
1204 (let ((block-start-regexp
1205 (python-rx line-start (* whitespace) block-start))
1206 (starting-pos (point)))
1207 (while (> arg 0)
1208 (python-nav-statement-end)
1209 (while (and
1210 (re-search-forward block-start-regexp nil t)
1211 (or (python-info-ppss-context 'string)
1212 (python-info-ppss-context 'comment)
1213 (python-info-ppss-context 'paren))))
1214 (setq arg (1- arg)))
1215 (while (< arg 0)
1216 (python-nav-statement-start)
1217 (while (and
1218 (re-search-backward block-start-regexp nil t)
1219 (or (python-info-ppss-context 'string)
1220 (python-info-ppss-context 'comment)
1221 (python-info-ppss-context 'paren))))
1222 (setq arg (1+ arg)))
1223 (python-nav-statement-start)
1224 (if (not (looking-at (python-rx block-start)))
1225 (and (goto-char starting-pos) nil)
1226 (and (not (= (point) starting-pos)) (point-marker)))))
1227
1228(defun python-nav-forward-sexp-function (&optional arg)
1229 "Move forward across one block of code.
1230With ARG, do it that many times. Negative arg -N means
1231move backward N times."
1232 (interactive "^p")
1233 (or arg (setq arg 1))
1234 (while (> arg 0)
1235 (let ((block-starting-pos
1236 (save-excursion (python-nav-block-start)))
1237 (block-ending-pos
1238 (save-excursion (python-nav-block-end)))
1239 (next-block-starting-pos
1240 (save-excursion (python-nav-forward-block))))
1241 (cond ((not block-starting-pos)
1242 (python-nav-forward-block))
1243 ((= (point) block-starting-pos)
1244 (if (or (not next-block-starting-pos)
1245 (< block-ending-pos next-block-starting-pos))
1246 (python-nav-block-end)
1247 (python-nav-forward-block)))
1248 ((= block-ending-pos (point))
1249 (let ((parent-block-end-pos
1250 (save-excursion
1251 (python-util-forward-comment)
1252 (python-nav-block-start)
1253 (python-nav-block-end))))
1254 (if (and parent-block-end-pos
1255 (or (not next-block-starting-pos)
1256 (> next-block-starting-pos parent-block-end-pos)))
1257 (goto-char parent-block-end-pos)
1258 (python-nav-forward-block))))
1259 (t (python-nav-block-end))))
1260 (setq arg (1- arg)))
1261 (while (< arg 0)
1262 (let* ((block-starting-pos
1263 (save-excursion (python-nav-block-start)))
1264 (block-ending-pos
1265 (save-excursion (python-nav-block-end)))
1266 (prev-block-ending-pos
1267 (save-excursion (when (python-nav-backward-block)
1268 (python-nav-block-end))))
1269 (prev-block-parent-ending-pos
1270 (save-excursion
1271 (when prev-block-ending-pos
1272 (goto-char prev-block-ending-pos)
1273 (python-util-forward-comment)
1274 (python-nav-block-start)
1275 (python-nav-block-end)))))
1276 (cond ((not block-ending-pos)
1277 (and (python-nav-backward-block)
1278 (python-nav-block-end)))
1279 ((= (point) block-ending-pos)
1280 (let ((candidates))
1281 (dolist (name
1282 '(prev-block-parent-ending-pos
1283 prev-block-ending-pos
1284 block-ending-pos
1285 block-starting-pos))
1286 (when (and (symbol-value name)
1287 (< (symbol-value name) (point)))
1288 (add-to-list 'candidates (symbol-value name))))
1289 (goto-char (apply 'max candidates))))
1290 ((> (point) block-ending-pos)
1291 (python-nav-block-end))
1292 ((= (point) block-starting-pos)
1293 (if (not (> (point) (or prev-block-ending-pos (point))))
1294 (python-nav-backward-block)
1295 (goto-char prev-block-ending-pos)
1296 (let ((parent-block-ending-pos
1297 (save-excursion
1298 (python-nav-forward-sexp-function)
1299 (and (not (looking-at (python-rx block-start)))
1300 (point)))))
1301 (when (and parent-block-ending-pos
1302 (> parent-block-ending-pos prev-block-ending-pos))
1303 (goto-char parent-block-ending-pos)))))
1304 (t (python-nav-block-start))))
1146 (setq arg (1+ arg)))) 1305 (setq arg (1+ arg))))
1147 1306
1148(defvar python-nav-list-defun-positions-cache nil) 1307(defvar python-nav-list-defun-positions-cache nil)
@@ -2766,6 +2925,20 @@ The type returned can be 'comment, 'string or 'paren."
2766 (beginning-of-line 1) 2925 (beginning-of-line 1)
2767 (looking-at python-nav-beginning-of-defun-regexp)))) 2926 (looking-at python-nav-beginning-of-defun-regexp))))
2768 2927
2928(defun python-info-current-line-comment-p ()
2929 "Check if current line is a comment line."
2930 (char-equal (or (char-after (+ (point) (current-indentation))) ?_) ?#))
2931
2932(defun python-info-current-line-empty-p ()
2933 "Check if current line is empty, ignoring whitespace."
2934 (save-excursion
2935 (beginning-of-line 1)
2936 (looking-at
2937 (python-rx line-start (* whitespace)
2938 (group (* not-newline))
2939 (* whitespace) line-end))
2940 (string-equal "" (match-string-no-properties 1))))
2941
2769 2942
2770;;; Utility functions 2943;;; Utility functions
2771 2944
@@ -2818,6 +2991,9 @@ if that value is non-nil."
2818 (set (make-local-variable 'parse-sexp-lookup-properties) t) 2991 (set (make-local-variable 'parse-sexp-lookup-properties) t)
2819 (set (make-local-variable 'parse-sexp-ignore-comments) t) 2992 (set (make-local-variable 'parse-sexp-ignore-comments) t)
2820 2993
2994 (set (make-local-variable 'forward-sexp-function)
2995 'python-nav-forward-sexp-function)
2996
2821 (set (make-local-variable 'font-lock-defaults) 2997 (set (make-local-variable 'font-lock-defaults)
2822 '(python-font-lock-keywords nil nil nil nil)) 2998 '(python-font-lock-keywords nil nil nil nil))
2823 2999