Skip to content
Browse files

More robust marking of Python strings.

 - Use the ppss to find the end of a string, works for strings that
   contain escaped delimiters.

 - Test for marking a string that contains an escaped delimiter.
  • Loading branch information...
1 parent 5608028 commit c44b1f81867c11bc1df0b0961963f71d91d47188 @fgeller fgeller committed
Showing with 26 additions and 12 deletions.
  1. +9 −0 features/fgallina-python-el-expansions.feature
  2. +17 −12 python-el-fgallina-expansions.el
9 features/fgallina-python-el-expansions.feature
@@ -21,6 +21,15 @@ Feature: fgallinas python.el expansions
And I press "C-@"
Then the region should be "X-Men: Wolverine"
+ Scenario: Mark region inside a string with escape delimiter.
+ Given I turn on python-mode
+ And there is no region selected
+ When I insert "'pre' + 'X-Men: Wol\'verine' + 'post'"
+ And I place the cursor between "r" and "i"
+ And I press "C-@"
+ And I press "C-@"
+ Then the region should be "X-Men: Wol\'verine"
Scenario: Mark region outside a string.
Given I turn on python-mode
And there is no region selected
29 python-el-fgallina-expansions.el
@@ -30,7 +30,9 @@
(require 'expand-region-core)
-(defvar er--python-string-delimiter "'\"")
+(defvar er--python-string-delimiter
+ "'\""
+ "Characters that delimit a Python string.")
; copied from @fgallina's python.el as a quick fix. The variable
; `python-rx-constituents' is not bound when we use the python-rx
@@ -42,21 +44,24 @@
"except" "finally" "for" "while" "with")
-(defun er/match-python-string-delimiter ()
- "Returns the Python string delimiter at point, if there is one."
- (looking-at "\\(\"\"\"\\|\"\\|'''\\|'\\)")
- (match-string 1))
(defun er/mark-python-string (mark-inside)
+ "Mark the Python string that surrounds point.
+If the optional MARK-INSIDE is not nil, only mark the region
+between the string delimiters, otherwise the region includes the
+delimiters as well."
(let ((beginning-of-string (python-info-ppss-context 'string (syntax-ppss))))
(when beginning-of-string
(goto-char beginning-of-string)
- (let ((string-delimiter (er/match-python-string-delimiter)))
- (search-forward string-delimiter nil nil 2)
- (when mark-inside (skip-chars-backward er--python-string-delimiter))
- (set-mark (point))
- (goto-char beginning-of-string)
- (when mark-inside (skip-chars-forward er--python-string-delimiter))))))
+ ;; Move inside the string, so we can use ppss to find the end of
+ ;; the string.
+ (skip-chars-forward er--python-string-delimiter)
+ (while (python-info-ppss-context 'string (syntax-ppss))
+ (forward-char 1))
+ (when mark-inside (skip-chars-backward er--python-string-delimiter))
+ (set-mark (point))
+ (goto-char beginning-of-string)
+ (when mark-inside (skip-chars-forward er--python-string-delimiter)))))
(defun er/mark-inside-python-string ()

0 comments on commit c44b1f8

Please sign in to comment.
Something went wrong with that request. Please try again.