Предположим, у меня есть буфер Emacs lisp, который содержит:
(defvar foo 1)
Если я позвоню eval-last-sexp
или eval-buffer
, это foo
будет связано с 1. Если я затем отредактирую этот буфер на:
(defvar foo 2)
eval-last-sexp
и eval-buffer
не повторять эту строку, так foo
что все равно 1.
Это особенно сложно, когда таких заявлений несколько, и мне нужно отследить, какие строки не переоцениваются.
Я посмотрел только на перезапуск Emacs и затем (require 'foo)
, но тогда я должен быть осторожен, чтобы не загружать старые файлы .elc.
Как я могу быть абсолютно уверен в том, что переменные и функции, определенные в текущем файле, находятся в том же состоянии, что и загрузка кода заново в новом экземпляре Emacs?
interactive-development
Уилфред Хьюз
источник
источник
makunbound
а затем пересмотреть код в буфере.(incf emacs-major-version)
с которыми я могу жить неоднократно. Я заинтересован во взломе кода с множествомdefvar
форм.Ответы:
Как объяснено в других ответах, оценка
defvar
формы с помощьюeval-last-sexp
не сбрасывает значение по умолчанию.Вместо этого, вы можете использовать
eval-defun
(обязаныC-M-x
вemacs-lisp-mode
по умолчанию), который реализует поведение , которое вы хотите в качестве особого исключения:Если вам нужно оценить все содержимое буфера, вы можете написать функцию, которая по очереди просматривает формы верхнего уровня и вызывает их
eval-defun
. Примерно так должно работать:источник
eval-defun
вместоeval-last-sexp
. Вы даже можете написать функцию, которая вызываетeval-defun
каждую форму в буфере, и использовать ее вместоeval-buffer
.eval-defun
вместоeval-last-sexp
, конечно, но сложность дляeval-buffer
.eval-defun
каждой формы верхнего уровня в буфере.defvar
не внутриdefun
. Пример:(progn (defvar foo "bar"))
.defconst
(которые всегда переоцениваются). Недавно в бесконечных скобкахКак и в других ответах, именно так работает defvar, но вы можете обойти это, в конце концов, это elisp.
Вы можете временно переопределить работу defvar, если хотите, и в течение этого времени перезагрузить пакеты, которые вы хотите сбросить.
Я написал макрос, в котором при оценке тела значения defvars всегда будут переоцениваться.
Пример использования:
file_a.el
file_b.el
Примечание. Это следует использовать только с целью переоценки defvars, поскольку при переоценке он просто игнорирует строки документации. Вы можете изменить макрос для поддержки переоценки, которая также применяет строки документов, но я оставлю это на ваше усмотрение.
В вашем случае вы могли бы сделать
Но знайте, что те, кто пишут elisp, делают так, ожидая, что defvar будет работать как указано, возможно, они используют defvar для определения и setq в некоторой функции init для указания значения, так что вы можете в конечном итоге обнулить переменные, которые вы не намереваетесь, но это, наверное, редко.
Альтернативная реализация
Используя это, вы можете просто переопределить defvar глобально и контролировать, будет ли он устанавливать значение символа в аргумент INIT-VALUE, даже если символ определяется путем изменения значения нового
defvar-always-reeval-values
символа.источник
defvar
является хорошей идеей: есть несколько возможных вариантов использованияdefvar
, с немного другой семантикой. Например, один из ваших макросов, который не учитывается, - это(defvar SYMBOL)
форма, которая используется, чтобы сообщить байт-компилятору о существовании переменной без установки значения.defvar
макрос, вам, скорее всего, лучше поставить префикс исходнойdefvar
формы с помощьюmakunbound
символа вместо его замены наsetq
.defvar
Проводится оценка и делать именно то , что вы указали. Тем не менее,defvar
только устанавливает начальное значение:Таким образом, чтобы достичь желаемого, вам нужно либо отменить привязку переменной перед повторной оценкой, например,
или используйте
setq
для установки значения, напримерЕсли вам не нужно указывать здесь строку документации, вы можете
defvar
вообще пропустить .Если вы действительно хотите использовать
defvar
и автоматически отсоединять это, вам нужно написать функцию для поискаdefvar
вызовов в текущем буфере (или области, или последнем сексе и т. Д.); позвонитьmakunbound
для каждого; а затем сделать фактический Eval.источник
eval-buffer
оберткой, которая сначала свяжет все, но ответ @ Francesco оeval-defun
том, что вы действительно хотите.Следующий макрос был создан путем отслеживания
eval-defun
его вспомогательных функций и изменения его таким образом, чтобы больше не требовалось оценивать область определенного буфера. Мне потребовалась помощь в соответствующей теме. Преобразование выражения в строку , и @Tobias пришел на помощь - научил меня, как преобразовать несовершенную функцию в макрос. Я не думаю, что мы должныeval-sexp-add-defvars
предшествоватьelisp--eval-defun-1
, но если кто-то считает, что это важно, пожалуйста, дайте мне знать.источник
Проблема не в том, что линия не переоценивается. Проблема в том, что
defvar
определяет переменную и ее значение по умолчанию . Если переменная уже существует, то изменение ее значения по умолчанию не изменяет текущее значение. К сожалению, я думаю, вам нужно будет запуститьsetq
для каждой переменной, значение которой вы хотите обновить.Это может быть излишним, но вы можете обновить свой файл, как этот, если вы хотите иметь возможность легко обновить
foo
его до нового значения по умолчанию.но это требует, чтобы вы поддерживали значение по умолчанию в двух местах в вашем коде. Вы также можете сделать это:
но если есть шанс, который
foo
объявлен в другом месте, вы можете столкнуться с некоторыми побочными эффектами.источник
eval-defun
лечитdefvar
специально, поэтому наверняка есть что-то похожее для целых буферов?makunbound
определять любые переменные, объявленные в текущем буфере, и затем переоценивать ее? Вы можете написать свой собственный, но я не думаю, что для этого есть готовая функция. РЕДАКТИРОВАТЬ: Неважно, я понимаю, что вы говорите. Этоeval-defun
работает на весь буфер. Похоже, у @JordonBiondo есть для этого решение.defvar
ничего не делает, если переменная уже имеет значение (как говорит ее документ:)The optional argument INITVALUE is evaluated, and used to set SYMBOL, only if SYMBOL's value is void.
. Проблема не в том, чтоdefvar
изменяется значение по умолчанию, а не текущее значение.(defvar a 4) (default-value 'a) (setq a 2) (default-value 'a)
; затемC-x C-e
послеdefvar
секса; тогда(default-value 'a)
.C-x C-e
,eval-region
И тому подобное наdefvar
Sexp ничего не изменить значение по умолчанию.