Як перенести два аргументи функції в Python?


11

Як я можу поміняти два аргументи під час виклику функції Python?

Якщо я поставлю pointпробіл між цими двома аргументами:

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

а потім M-t( transpose-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
Я не пробував, але для цього можна використовувати прив’язаний перенос ; це, однак, двоетапний процес.
Каушал Моді

Існує основна функція, transpose-subrяка називається, яка приймає forwardфункцію і переводить її у transposeфункцію. Отже, якби у нас була c-forward-arglist(функція переходити від однієї аргументації функції до іншої - AFAICT ця не існує) у нас була б c-transpose-arglist.
Брендан

Відповіді:


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 виправлення було відносно легким (див. Вище). Найцікавіше, що я намагався виконувати поради Стефана, написавши альтернативу forward-sexp-function, і це виявилося занадто громіздким через коми. Потім я спробував копіювати, traspose-sexpщоб зробити те саме, і, знову ж таки, необхідність врахувати коми робить це дуже важко. Я не стверджую, що це завжди робить правильно, якщо мова йде про обмежувачі списку, можливо, лише половину часу ...
wvxvw

Це не вдається, (aa, bb)коли курсор увімкнено першим a. Це також не працює для переміщення. FOO(aaa *, bbb, ccc)Як- *небудь псується транспонування.
ideaman42

Також не працює для 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

1
Це не працює для аргументів ключових слів на кшталт: f(a=1, b=2)(це переміщається навколо)
Att Righ

1
Хоча питання про код C, ця відповідь працює для f(a=1, b=2)- emacs.stackexchange.com/a/47930/2418
ideaman42

2

У режимах, які використовують SMIE, transpose-sexpслід правильно працювати в цьому випадку. Вони все одно не зможуть, коли символ інфіксації (він же "роздільник") не є ,(або a ;), а є словом (наприклад and).

Отже, моя думка полягає в тому, що команда для цього є, transpose-sexpі коли це працює не правильно, я вважаю це помилкою (але помилка, яка може бути важкою та / або потребує часу, щоб виправити і мати низький пріоритет, тому не ' т затримати дихання). Спосіб її виправити - це встановити forward-sexp-functionфункцію, яка буде знати, що "після того, як я побачу кому, я просто стрибаю весь аргумент".


1
Я думаю, що режим java (наприклад) не використовує SMIE? Як би можна було вирішити це?
Семюель Едвін Уорд

1
Ні, дійсно, основні режими для мов, подібних до C, не використовують SMIE і не лише з історичних причин: аналізатор SMIE просто занадто слабкий для цих мов. Це означає, що парсер SMIE буде добре працювати, якщо ви хочете поміняти місцями два аргументи, розділені комою (ця частина граматики є досить простою), тож я думаю, можна було б налаштувати SMIE і використовувати його, forward-sexp-functionале ви б мали додати якийсь код, щоб використовувати SMIE лише forward-sexp-function в тих випадках, коли він працює досить добре, оскільки у багатьох інших випадках це призведе до заплутаної поведінки.
Стефан
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.