Emacs: как оценить наименьшее s-выражение, в котором находится курсор, или следующее s-выражение

Как правильно оценить часть (+ 100 (+ 100 100)) в

(+ (+ 1 2) (+ 100 (+ 100 100)))

?

На данный момент я делаю это C-x C-e, что означает, что мне нужно найти конечную скобку, что в большинстве случаев сложно. Options > Paren Matching Highlighting помогает, но мне все равно нужно перемещать курсор к конечной скобке, пока выделенное совпадение не станет начальной скобкой.

Одним из способов было бы иметь обратную версию C-x C-e, чтобы я мог поместить курсор в начальную скобку следующим образом:

(+ (+ 1 2) |(+ 100 (+ 100 100)))

а затем нажмите соответствующую комбинацию клавиш.

Или я мог бы поместить курсор внутри выражения, но не внутри меньших выражений:

(+ (+ 1 2) (+ | 100 (+ 100 100)))

и нажмите привязку клавиш. Потому что целиться в цель легче, если цель большая.

Как сделать такую ​​команду? Или он уже предоставлен?

Боковое примечание: курсор в виде полосы и курсор в виде рамки

Пользователи Emacs, использующие курсор в виде прямоугольника (по умолчанию), могут задаться вопросом, куда я помещаю курсор с обозначением полосы выше. В emacs вы можете выбрать курсор в виде прямоугольника или курсор в виде полосы, (bar-cursor-mode t). Когда курсор в виде полосы находится между буквами A и B, курсор в рамке находится на B. Таким образом, полоса — это левая стенка коробки.

Кстати, концепция курсора в виде полосы полезна необычным образом: практика итерации от index1 до index2-1 в программировании удивляет новичков. Это помогает представить index1 и index2 как указывающие полосы (левые стены), а не прямоугольники.


person Yoo    schedule 31.01.2010    source источник


Ответы (4)


Привяжите ключ к одному или обоим из них:

(defun eval-next-sexp ()
  (interactive)
  (save-excursion
    (forward-sexp)
    (eval-last-sexp nil)))

(defun eval-surrounding-sexp (levels)
  (interactive "p")
  (save-excursion
    (up-list (abs levels))
    (eval-last-sexp nil)))

По касательной, я настоятельно рекомендую paredit для работы с s-выражениями. Команды редактирования структуры и привязки упрощают редактирование s-выражений. Она связывает C-down с up-list, так что eval-surrounding-sexp выше почти точно такое же, как C-down C-x C-e (единственное отличие состоит в том, что функция использует save-excursion для предотвращения движения).

person Chris Johnsen    schedule 31.01.2010

Вы можете написать такую ​​команду так:

(require 'thingatpt)
(defun eval-sexp-at-or-surrounding-pt ()
  "evaluate the sexp following the point, or surrounding the point"
  (interactive)
  (save-excursion
    (forward-char 1)
    (if (search-backward "(" nil t)
        (message "%s" (eval (read-from-whole-string (thing-at-point 'sexp)))))))
person Trey Jackson    schedule 31.01.2010

В разделе Сосульки есть это общий способ делать то, что вы хотите.

По умолчанию в минибуфере M-. привязан к команде, которая вставляет текст в точку (или рядом с ней) в минибуфер (не вводит ее и не делает с ней что-то еще, а просто вставляет ее).

Например, вы можете использовать M-: для оценки sexp Лиспа, а затем использовать M-. для получения sexp в точке или рядом с ней.

Если вы повторяете M-., то он отбрасывает то, что только что захватил, и захватывает какую-то другую ВЕЩЬ (текст) в точке или рядом с ней и вставляет ее. По умолчанию он проходит через эти виды ВЕЩЕЙ по порядку:

а. Символ Лиспа или имя файла.

б. Активная область (выделенный текст) или слово.

в. Самый ближайший список.

д. Следующий по величине список.

е. Следующий по величине список.

ф. Какой бы файл или URL ни угадывала функция ffap-guesser.

г. Какой бы URL ни угадывала функция thing-at-point-url-at-point.

Что это означает для вашего примера (+ (+ 1 2) (+ 100 (+ 100 100)))?

Например, если точка находится перед 1 предпоследнего 100, это секспсы, которые последовательно вставляются в минибуфер, когда вы повторно нажимаете M-., в следующем порядке:

a. +

b. 100

c. (+ 100 100)

d. (+ 100 (+ 100 100))

e. (+ (+ 1 2) (+ 100 (+ 100 100)))?

Таким образом, чтобы вставить самый большой из вложенных списков, вы должны сделать M-: M-. М-. М-. М-. M-., то есть нажмите M-. пять раз.

Для такого поведения, в частности для точного захвата списков, вам также потребуется библиотека Thing At Точка+.

person Drew    schedule 21.08.2011

Есть встроенный eval-defun. По умолчанию он привязан к C-M-x. Это похоже на то, что вы хотите, но оценивает определение верхнего уровня. Возможно, вы сможете это адаптировать.

person Noufal Ibrahim    schedule 31.01.2010
comment
eval-defun захватит слишком много (вся форма верхнего уровня, которая содержит или идет после точки). ОП явно хочет оценить только внутреннее подвыражение. - person Chris Johnsen; 31.01.2010
comment
Ага. Я предлагал адаптировать это. Особенно то, как он находит секс на высшем уровне. - person Noufal Ibrahim; 31.01.2010