วิธีโอนย้ายอาร์กิวเมนต์สองข้อของฟังก์ชันใน 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
ฉันไม่ได้ลอง แต่Anchored Transposeสามารถใช้ได้ มันเป็นกระบวนการ 2 ขั้นตอน
Kaushal Modi

มีฟังก์ชั่นหลักที่เรียกว่า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))))

ฉันได้รับเมื่อจุดอยู่ในช่องว่าง (ทำงานเมื่ออยู่บนเครื่องหมายจุลภาค): ให้ *: อาร์กิวเมนต์ประเภทที่ไม่ถูกต้อง: จำนวนเต็มหรือเครื่องหมาย -p, ไม่มี
Croad Langshan

@CroadLangshan การแก้ไขค่อนข้างง่าย (ดูด้านบน) สิ่งที่ตลกที่ฉันพยายามทำตามคำแนะนำของสเตฟานด้วยการเขียนทางเลือกforward-sexp-functionและดูเหมือนว่าจะยุ่งยากเกินไปเพราะคอมม่า จากนั้นฉันพยายามเลียนแบบtraspose-sexpเพื่อทำสิ่งเดียวกันและอีกครั้งที่ต้องใช้เครื่องหมายจุลภาคทำให้ยากมาก ฉันไม่ได้อ้างว่าสิ่งนี้ทำในสิ่งที่ถูกต้องเสมอเมื่อพูดถึงรายการตัวคั่นบางทีอาจจะแค่ครึ่งเดียวเท่านั้น ...
wvxvw

นี้ล้มเหลวเมื่อเคอร์เซอร์อยู่ในวันแรก(aa, bb) aสิ่งนี้ยังใช้งานไม่ได้สำหรับFOO(aaa *, bbb, ccc)การ*เคลื่อนย้าย
ideasman42

ล้มเหลวด้วยสำหรับFOO(&aaa, bbb)(& ไม่สลับ)
ideasman42

4

ฉันจะใช้รูปแบบของtranspose-sexpsรูปลักษณ์ที่ว่าสำหรับกรณีที่คุณอธิบายและ transposes 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
ในขณะที่คำถามคือ abount รหัส C คำตอบนี้ใช้ได้กับf(a=1, b=2)- emacs.stackexchange.com/a/47930/2418
ideasman42

2

ในโหมดที่ใช้ SMIE transpose-sexpควรทำงานอย่างถูกต้องสำหรับกรณีนั้น พวกเขาจะยังคงล้มเหลวเมื่อสัญลักษณ์ infix (aka "ตัวคั่น") ไม่ใช่,(หรือ;) แต่เป็นคำ (เช่นand)

ดังนั้นความเห็นของฉันคือคำสั่งสำหรับสิ่งนั้นtranspose-sexpและเมื่อสิ่งนี้ทำงานไม่ถูกต้องฉันถือว่ามันเป็นข้อผิดพลาด (แต่ข้อผิดพลาดที่อาจยากและ / หรือใช้เวลาในการแก้ไขและมีลำดับความสำคัญต่ำดังนั้นอย่า ' อย่ากลั้นลมหายใจของคุณ) วิธีการแก้ไขคือการตั้งค่าforward-sexp-functionฟังก์ชั่นที่จะรู้ว่า "หลังจากที่ฉันเห็นเครื่องหมายจุลภาคฉันเพิ่งกระโดดไปรอบ ๆ อาร์กิวเมนต์ทั้งหมด"


1
ฉันเดาโหมด java (ตัวอย่าง) ไม่ใช้ SMIE? เราจะแก้ไขมันอย่างไร?
ซามูเอลเอ็ดวินวอร์ด

1
ไม่แน่นอนโหมดหลักสำหรับภาษาที่เหมือน C ไม่ได้ใช้ SMIE และไม่เพียง แต่ด้วยเหตุผลทางประวัติศาสตร์: ตัวแยกวิเคราะห์ของ SMIE อ่อนแอเกินไปสำหรับภาษาเหล่านั้น สิ่งนี้กล่าวว่าตัวแยกวิเคราะห์ของ SMIE จะทำงานได้ดีถ้าคุณต้องการสลับอาร์กิวเมนต์สองตัวคั่นด้วยเครื่องหมายจุลภาค (ส่วนนี้ของไวยากรณ์นั้นง่ายพอ) ดังนั้นฉันเดาว่ามันจะเป็นไปได้ที่จะกำหนดค่า SMIE และใช้งานได้forward-sexp-functionแต่คุณต้องการ เพื่อเพิ่มรหัสบางอย่างเพื่อใช้ SMIE forward-sexp-function ในกรณีที่มันทำงานได้ดีพอเนื่องจากในหลายกรณีมันจะส่งผลให้เกิดพฤติกรรมที่สับสน
สเตฟาน
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.