[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
До того, как я научу вас создавать собственные функции на Emacs Lisp, полезно немного попрактиковаться в вычислении различных выражений, которые уже написаны. Эти выражения будут списками, где первый и часто единственный элемент списка --- имя какой-нибудь функции. Так как одни из самых простых функций в Emacs --- это функции связанные с буферами, то мы начнем с них; к тому же они очень интересны и познавательные. В этой главе мы изучим наиболее простые из этих функций. В следующей главе разберемся с более сложными функциями, связанными с буферами Emacs, и мы увидим, как они реализованы на Emacs Lisp.
C-x C-e вы заставляете интерпретатор
Как вычислить
работать.
буфера.
2.1 Имя буфера 2.2 Как вернуть буфер 2.3 Смена буфера 2.4 Размер буфера и местоположение точки
2.5 Упражнения
Когда вы выполняете какую-нибудь команду редактирования, такую как перемещение курсора или прокрутка экрана, вы вычисляете выражение, первым элементом которого является функция. Именно так и работает Emacs.
Когда вы нажимаете клавиши, вы заставляете интерпретатор Лиспа
вычислить выражение, и так вы получаете результаты. Даже просто
набирая какой-нибудь текст, вы вычисляете функцию, в данном случае
self-insert-command
, которая просто вставляет в текст набранные
вами символы. Функции, которые вы вычисляете нажатием клавиш,
называются `интерактивными' функциями, или командами; как
сделать функцию интерактивной показано в следующей главе, где мы
научимся определять собственные функции в Emacs Лисп.
See section Making a Function Interactive.
Кроме выполнения интерактивных команд, мы уже знаем другой способ вычислить выражение --- расположить курсор после списка и нажать C-x C-e. Именно так мы и будем делать до конца этой главы. Существуют и другие способы вычислить выражение --- они будут описаны в последующих главах.
Можно добавить, что функции, которые мы будем вычислять до конца этой главы, полезны сами по себе. Изучение этих функций поможет понять разницу между буферами и файлами; каким образом можно переключиться в нужный буфер, и как определить положение курсора в текущем буфере.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Две функции, buffer-name
и buffer-file-name
, показывают
разницу между файлом и буфером. Когда вы вычислите следующее
выражение, (buffer-name)
, в эхо-области появиться имя этого
буфера. Когда вы вычислите (buffer-file-name)
, в эхо-области
появится имя файла, соответствующего данному буферу. Обычно имя,
которое возвращает функция (buffer-name)
--- это имя
редактируемого файла, а имя, возвращаемое (buffer-file-name)
полное имя файла (вместе с именами каталогов).
Файл и буфер --- это два совершенно различных понятия. Файл --- это информация хранимая в компьютере постоянно (если вы конечно не удалите его сами). Буфер, наоборот --- это информация, которая хранится в Emacs и она пропадет в конце сессии редактирования (или когда вы уничтожите буфер). Обычно буфер содержит информацию, которую вы скопировали из файла; мы говорим, что буфер посетил этот файл. Именно эту копию вы изменяете. Изменения в буфере не меняют содержимое файла до тех пор, пока вы не сохраните буфер. Когда вы сохраняете буфер, он копируется обратно в файл, и таким образом все изменения фиксируются постоянно.
Если вы читаете это в Info внутри GNU Emacs, то вы можете вычислить каждое из следующих выражений, расположив курсор после него и нажав C-x C-e.
(buffer-name) (buffer-file-name) |
Когда я сделал это, в эхо-области появилась строка
`"introduction.texinfo"' --- это значение, которое вернула
функция (buffer-name)
, функция (buffer-file-name)
вернула другое значение `"/gnu/work/intro/introduction.texinfo"'.
Первое --- это имя буфера, а второе --- это имя файла. (При
вычислении этих выражений круглые скобки говорят интерпретатору Лисп
обрабатывать buffer-name
и buffer-file-name
как функции;
без скобок интерпретатор попытается вычислить эти символы как
переменные).
Несмотря на существующую разницу между файлами и буферами, вы часто обнаруживаете, что люди говорят о файле, когда они имеют ввиду буфер и наоборот. В самом деле, большинство говорит, "Я редактирую файл" а, не "Я редактирую буфер, который вскоре сохраню в файле." Однако из контекста почти всегда ясно, что они имеет ввиду. Однако когда дело касается компьютерных программ очень важно понимать эту разницу, так как компьютеры не так сообразительны как люди.
Слово `буфер' между прочим первоначально означало подушку, которая смягчает силу коллизии. В старых компьютерах буфер смягчал коллизии между файлами и центральным процессором. Барабаны и ленты, которые содержали файл и процессор были устройствами, которые очень отличались друг от друга и работали с разной скоростью, рывками. Буфер позволял таким различным устройствам сосуществовать вместе, и эффективно работать. Постепенно буфер превратился из промежуточного временного устройства в то место, где происходить основная работа. Это превращение похоже на то, как маленький портовый городишко превратился в огромный мегаполис --- когда-то это было место, где команда отдыхала на временной стоянке, а теперь это крупный культурный и деловой центр.
Не все буфера связаны с существующими файлами. Например, когда вы
запускаете сессию Emacs, набрав команду emacs
в командной
строке, не перечисляя никаких файлов, то Emacs вначале отобразит на
экране буфер `*scratch*'. Этот буфер не связан ни с каким файлом.
То же самое можно сказать про буфер `*Help*'.
Если вы переключитесь в буфер `*scratch*' наберете
(buffer-name)
, поставите курсор после этого выражения и нажмете
C-x C-e, чтобы вычислить его, то в эхо-области появится имя
"*scratch*"
, как результат вычисления данной функции.
"*scratch*"
--- это имя буфера. Однако, если вы попробуете
вычислить выражение (buffer-file-name)
, находясь в буфере
`*scratch*', то в эхо-области появится nil
. nil
--- это `ничего' в переводе с латинского; в нашем случае это
означает, что буфер `*scratch*' не связан ни с каким из файлов.
(В Лиспе, nil
также используют в значении `ложь' и также как
синоним для пустого списка, ()
.)
Кстати, если вы находитесь в буфере `*scratch*' и хотите, чтобы возвращаемое значение появилось в самом буфере `*scratch*', а не в эхо-области, то нажмите C-u C-x C-e вместо C-x C-e. Тогда возвращенное значение появится после выражения. Буфер будет выглядеть следующим образом:
(buffer-name)"*scratch*" |
Вы не сможете выполнить этого в Info, поскольку буфер Info открыт в режиме только для чтения, и поэтому в нем запрещены какие-либо изменения. Но вы можете сделать так в любом буфере, который вы можете изменять; а когда вы пишете программы или документацию (например такую книгу), то такая возможность очень полезна.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Функция buffer-name
возражает имя буфера; чтобы получить
сам буфер, нужна другая функция: current-buffer
. Вы
можете использовать эту функцию в своих программах, когда вам надо
получить сам буфер.
Имя и объект, или сущность, к которой относится это имя отличаются
друг от друга. Вы --- не ваше имя. Вы личность, к которой другие
люди могут обращаться по имени. Если вы захотите поговорить с Джоном,
и кто-то протянет вам лист бумаги с буквами `Д', `ж',
`о', `'н', вас это может быть позабавит, но вы же хотели
совсем другого. Вы не хотите разговаривать с именем, вам нужен
человек, которого так зовут. С буфером дело обстоит таким же
образом --- имя буфера scratch это `*scratch*', но имя это не
сам буфер. Чтобы получить сам буфер вам нужна какая-нибудь функция
--- например current-buffer
.
Однако существует определенная тонкость --- если вы вычислите
выражение current-buffer
в каком-нибудь выражении, как мы
вскоре и сделаем, то, то что вы увидите --- это печатное
представление буфера без его содержимого. Emacs делает это по двум
причинам --- в буфере может быть тысячи строк (это неудобно
отображать) и другой буфер может иметь такое же содержание, и очень
важно отличать их друг от друга.
Ниже выражение с нужной нам функцией:
(current-buffer) |
Если вы вычислите это выражение, как обычно, то в эхо-области появится `#<buffer *info*>'. Особый формат показывает, что функция возвращает буфер, а не его имя.
Кстати, хотя вы можете использовать в своих программах числа и
символы, вы не можете делать это с печатным представлением буфера
--- единственный способ получить буфер в вашей программе, это
использовать функцию такую как current-buffer
.
Похожая функция other-buffer
. Она возвращает буфер, в котором
вы недавно побывали. Если вы переключитесь в буфер `*scratch*' ,
а затем вернетесь обратно, то функция other-buffer
вернет буфер
`#<buffer *scratch*>'.
Вы можете проверить это, вычислив следующее выражение:
(other-buffer) |
В эхо-области появится `#<buffer *scratch*>' или имя какого-нибудь другого буфера, из которого вы недавно переключились.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Функции, возвращающие буфер, обычно используют в более сложных
выражениях --- например, когда какой-нибудь функции требуется
буфер как один из ее аргументов. Мы увидим это на примере функции
switch-to-buffer
, которая используется для перекления в другой
буфер.
Но вначале краткое введение в функцию switch-to-buffer
. Когда
вы переключаетесь из буфера Info в буфер `*scratch*' и обратно,
вычисляя (buffer-name)
, то вы обычно нажимает C-x b и
затем в мини-буфере вводите `*scratch*' в качестве имени буфера,
в который вы хотите переключиться. Нажатие клавиш C-x b
заставляет интерпретатор Лиспа вычислить интерактивную функцию Emacs
Lisp switch-to-buffer
. Как мы уже говорили, именно так и
работает Emacs --- разные клавиши вызывают или запускают разные
функции. Например, C-f вызывает forward-char
, M-e
вызывает forward-sentence
, и так далее.
Написав выражение с функцией switch-to-buffer
и задав ей буфер,
в который мы хотим переключиться, в качестве аргумента, мы можем
переключится в этот буфер аналогично тому, как мы это делаем, нажимая
сочетание клавиш C-x b.
Вот необходимое Лисп выражение:
(switch-to-buffer (other-buffer)) |
Символ switch-to-buffer
--- первый элемент списка, поэтому
интерпретатор будет обрабатывать его как функцию и выполнит
соответствующие ей инструкции. Но до того, как вызвать эту функцию,
интерпретатор заметит внутренний вложенный список
(other-buffer)
и сначала вычислит внутреннее выражение.
other-buffer
первый (и в нашем случае единственный) элемент
внутреннего списка, так что интерпретатор Лиспа вызовет или запустит
эту функцию. Она возвратит другой буфер. Затем интерпретатор вызовет
switch-to-buffer
, передав ей в качестве аргумента другой буфер,
в который Emacs и переключится. Если вы читаете это в Info, попробуйте
это прямо сейчас. Вычислите выражение. (Чтобы вернуться обратно,
нажмите C-x b RET).
В последующих главах вы будете встречать функцию set-buffer
чаще чем switch-to-buffer
. Это потому, что между людьми и
компьютерными программами существует разница --- у людей есть
глаза, и они привыкли видеть то, над чем они сейчас работают. Это
настолько ясно, что об этом даже не говорят. Однако у программ нет
глаз. Когда компьютерная программа работает над буфером, его
необязательно отображать на экране компьютера.
switch-to-buffer
предназначена для людей и выполняет две разные
вещи --- она переключает внимание Emacs на какой-нибудь буфер; и
отображает новый выбранный буфер на экране компьютера.
set-buffer
, действует немного по-другому, эта функция делает
только одно --- она переключает внимание компьютерной программы на
другой буфер. Буфер, отображаемый на экране компьютера, остается без
изменений (конечно, там обычно ничего не произойдет до тех пор, пока
программа не завершится).
Также, мы недавно использовали другой термин из сленга программистов --- слово вызывать. Когда вы вычисляете список, в котором первый символ это имя функции, то вы вызываете эту функцию. Этот термин появился, когда заметили, что функция --- это сущность которая может выполнить что нибудь для вас, если вы вызовете ее (как водопроводчик сущность, которая может устранить утечку, если вы вызовете его).
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
В конце главы давайте обратимся к совсем простым функциям:
buffer-size
, point
, point-min
и point-max
.
Они дают информацию о размере буфера и местоположении точки в нем.
Функция buffer-size
показывает размер текущего буфера; то есть
эта функция возвращает число символов в данном буфере.
(buffer-size) |
Вы можете вычислить это как обычно, расположив курсор за выражением и нажав C-x C-e.
В Emacs текущая позиция курсора называется точкой. Выражение
(point)
возвращает число, которое сообщает вам, где расположен
курсор, считая символы от начала буфера до точки.
Вы можете увидеть число символов для текущего положения курсора в этом буфере, вычислив следующее выражение обычным способом:
(point) |
Когда я сам вычислил это выражение, значение точки было 65724.
Функция point
часто используется в последующих примерах этой
книги.
Значение точки зависит, конечно, от ее местоположения внутри буфера. Если вы вычислите следующее выражение, то число будет больше:
(point) |
Для меня значение точки в этом месте было 66043 --- это означает, что между этими двумя выражениями 319 символов (включая пробелы).
Функция point-min
очень похожа на point
, но она
возвращает минимально возможное значение точки в текущем буфере.
Обычно это число 1, если не включено сужение ("narrowing").
(Сужение --- это механизм, каким вы можете ограничить себя или
программу для действия только на части буфера. See section Narrowing and Widening.)) Аналогично, функция
point-max
возвращает максимально возможное значение точки в
текущем буфере.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Откройте какой-нибудь текстовый файл и переместите курсор в середину этого файла. Найдите имя файла, имя буфера, его длину, и вашу текущую позицию в нем.
[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |