如何在Python中转置函数的两个参数?


11

如何在调用Python函数时交换两个参数?

如果我point在这两个参数之间加上空格:

self.assertEqual(json.loads(some.data), json_data)

然后M-ttranspose-words),我得到:

self.assertEqual(json.loads(some.json), data_data)

另一方面,使用CMt(transpose-sexps),我得到:

self.assertEqual(json.loadsjson_data, (some.data))

我想要的是:

self.assertEqual(json_data, json.loads(some.data))

有命令可以做到这一点吗?


2
我没有尝试过,但是锚定转置可以用于此目的。这是一个两步过程。
2015年

有一个称为的核心函数transpose-subr,它接受一个forward函数并将其转换为一个transpose函数。因此,如果我们拥有c-forward-arglist(将功能从一个功能arg移至下一个AFAICT的功能,该功能将不存在),我们将拥有c-transpose-arglist
布伦丹

Answers:


4

这也是我很长时间以来一直希望拥有的东西,在这里,我找到了一些动力去做。它可能不是很健壮,但是在第一次尝试时,它似乎涵盖了我尝试过的情况:

(defun my/calculate-stops ()
  (save-excursion
    (let ((start
           (condition-case e
               (while t (backward-sexp))
             (error (point))))
          stops)
      (push start stops)
      (condition-case e
          (while t
            (forward-sexp)
            (when (looking-at "\\s-*,")
              (push (point) stops)))
        (error (push (point) stops)))
      (nreverse stops))))

(defun my/transpose-args ()
  (interactive)
  (when (looking-at "\\s-") (backward-sexp))
  (cl-loop with p = (point)
           with previous = nil
           for stop on (my/calculate-stops)
           for i upfrom 0
           when (<= p (car stop)) do
           (when previous
             (let* ((end (cadr stop))
                    (whole (buffer-substring previous end))
                    middle last)
               (delete-region previous end)
               (goto-char previous)
               (setf middle (if (> i 1) (- (car stop) previous)
                              (string-match "[^, \\t]" whole 
                                            (- (car stop) previous)))
                     last (if (> i 1) (substring whole 0 middle)
                            (concat (substring whole (- (car stop) previous) middle)
                                    (substring whole 0 (- (car stop) previous)))))
               (insert (substring whole middle) last)))
           (cl-return)
           end do (setf previous (car stop))))

当点在空格上时(在逗号上起作用),我得到了:let *:错误的参数类型:integer-or-marker-p,nil
Croad Langshan

@CroadLangshan的修复相对容易(参见上文)。我尝试通过编写替代方法来遵循Stefan的建议的有趣的事情forward-sexp-function,由于逗号的原因,这似乎太麻烦了。然后,我试图模仿traspose-sexp自己做同样的事情,而且,必须考虑逗号,这确实很困难。我并不是说这在列表分隔符方面总是做对的,也许只有一半的时间...
wvxvw 2015年

(aa, bb)当光标位于第一个上时,此操作将失败a。这也并不为调换工作FOO(aaa *, bbb, ccc)*莫名其妙搅乱变调。
ideaman42 '19

也因FOO(&aaa, bbb)(&不交换)而失败。
ideaman42

4

我使用一种变体transpose-sexps来查找您描述和转置按逗号分隔的情况的情况,或者只是进行常规的情况transpose-sexps。它还将光标留在原处,而不是将其向前拖动,这有点不同,但我个人很喜欢。

(defun my-transpose-sexps ()
  "If point is after certain chars transpose chunks around that.
Otherwise transpose sexps."
  (interactive "*")
  (if (not (looking-back "[,]\\s-*" (point-at-bol)))
      (progn (transpose-sexps 1) (forward-sexp -1))
    (let ((beg (point)) end rhs lhs)
      (while (and (not (eobp))
                  (not (looking-at "\\s-*\\([,]\\|\\s)\\)")))
        (forward-sexp 1))
      (setq rhs (buffer-substring beg (point)))
      (delete-region beg (point))
      (re-search-backward "[,]\\s-*" nil t)
      (setq beg (point))
      (while (and (not (bobp))
                  (not (looking-back "\\([,]\\|\\s(\\)\\s-*" (point-at-bol))))
        (forward-sexp -1))
      (setq lhs (buffer-substring beg (point)))
      (delete-region beg (point))
      (insert rhs)
      (re-search-forward "[,]\\s-*" nil t)
      (save-excursion
        (insert lhs)))))

对我来说,这在assertEqual调用的开始处留有空格(从空间上的点开始)。
Croad Langshan'5

1
这不适用于关键字参数,例如:(f(a=1, b=2)它会转置)
Att Righ

1
虽然问题是abount C代码,这个答案工程f(a=1, b=2)- emacs.stackexchange.com/a/47930/2418
ideasman42

2

在使用SMIE的模式下,transpose-sexp在这种情况下应该可以正常工作。当中缀符号(也称为“分隔符”)不是,(或;)而是一个词(例如and)时,它们仍然会失败。

因此,我认为命令是transpose-sexp正确的,并且当此命令无法正常运行时,我将其视为一个错误(但该错误可能很难实现和/或需要花费时间进行修复且优先级较低,因此请不要这样做)屏住呼吸)。解决此问题的方法是设置forward-sexp-function一个函数,该函数将知道“在看到逗号后,我会跳过整个参数”。


1
我猜Java模式(例如)不使用SMIE?如何解决这个问题?
塞缪尔·埃德温·沃德

1
的确,不,确实,类C语言的主要模式不使用SMIE,不仅是出于历史原因:SMIE的解析器对于那些语言来说太弱了。这就是说,SMIE的解析器会工作得很好,如果你想交换两个参数分开用逗号(语法这部分是很简单的),所以我想这将是可以配置SMIE,并使用它forward-sexp-function,但你必须添加一些代码以仅forward-sexp-function 在SMIE 运行良好的情况下使用SMIE ,因为在许多其他情况下,这将导致混乱的行为。
Stefan 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.