Emacs: extraindo trechos para outros arquivos

Requisitos

Se tiver dificuldade com o tutorial, sugiro que faça o tutorial do emacs. Para acessá-lo, basta abrir o emacs e pressionar, mantendo a tecla control (Ctrl) pressionada, pressionar h, e em seguida pressionar t. De outro modo (como você logo se acostumará a ver)

  1. C-h t

Além da tecla control, a tecla alt (também chamada meta) é bastante usada. Como usual, vamos representar essa tecla por M, e M-d significa pressionar d mantendo alt pressionado (esse comando apaga a próxima palavra no buffer — a palavra que segue o cursor no emacs).

Desafio

Queremos mover trechos de um texto para arquivos separados e numerados e numerados sequencialmente, substituindo sua ocorrência no texto original por alguma referência ao arquivo (seu nome, ou algum texto que contenha seu nome ou número).

Uma descrição mais precisa

Suposições

Os trechos são delimitados por alguma sequencia de caracteres conhecida. Por exemplo, se Início do trecho e Fim do trecho. sempre rodeiam as ocorrências do trecho de interesse, um exemplo do tipo de texto que queremos tratar é

 

 

 

  1. ARQUIVO: texto-original
  2. -----------------------
  3.  
  4. Este é *O* arquivo. Ele pode começar com qualquer coisa...
  5.  
  6. Início do trecho: este texto aqui é um dos que será movido para
  7. outro arquivo. Fim do trecho.
  8.  
  9. Aqui está texto que NÃO queremos alterar.
  10. ...
  11.  
  12. Início do trecho: mais coisa que vai para um arquivo. O arquivo
  13. com este trecho deve ser mandado para um arquivo com número
  14. seguinte ao outro. Fim do trecho.
  15.  
  16. O arquivo texto-original termina aqui.

A numeração deve preservar a ordem em que os trechos ocorrem no texto, como você deve ter imaginado.

Vamos supor também que os delimitadores serão movidos junto com o trecho para os arquivos que criarmos. Chamando os arquivos novos de trecho-X, em que X é o número do trecho, e substituindo os trechos movidos pelo texto Veja o arquivo trecho-X. (X é o número do trecho que estava ali) ficaríamos com o seguinte.

IMPORTANTE: estamos supondo aqui que não existem arquivos chamados trecho-X no diretório em que está o arquivo!! Para evitar deslizes, pode ser interessante colocar os trechos em uma pasta separada (isso é fácil de fazer, e vamos apontar como proceder mais adiante).

  1. ARQUIVO: texto-original
  2. -----------------------
  3.  
  4. Este é O arquivo. Ele pode começar com qualquer coisa...
  5.  
  6. Veja o arquivo trecho-1.
  7.  
  8. Aqui está texto que NÃO queremos alterar.
  9. ...
  10.  
  11. Veja o arquivo trecho-2.
  12.  
  13. O arquivo texto-original termina aqui.

E os arquivos trecho-1 e trecho-2 ficam como segue.

  1. ARQUIVO: trecho-1
  2. -----------------
  3.  
  4. Início do trecho: este texto aqui é um dos que será movido para
  5. outro arquivo. Fim do trecho.

ARQUIVO: trecho-2

  1. Início do trecho: mais coisa que vai para um arquivo. O arquivo
  2. com este trecho deve ser mandado para um arquivo com número
  3. seguinte ao outro. Fim do trecho.

Estratégia

Queremos definir uma macro que

  1. Procura a próxima ocorrência de Início do trecho,
  2. Move o trecho para o arquivo trecho-X , com X apropriado e
  3. Escreve Veja o arquivo trecho-X no lugar em que o trecho estava.

1 Buscando o início do trecho

Podemos usar a busca incremental C-s (control-s)

  1. C-s Início do trecho

O nome "incremental" vem de que a busca é feita à medida que se digita o texto. Essa busca começa a partir do ponto em que está o cursor, então, se você quiser pegar a primeira ocorrência no buffer aberto, precisa que ele estaja posicionado antes dela. (Você consegue ir para o começo do buffer com M-<.

Isso posiciona o cursor no fim da primeira ocorrência encontrada. Mas queremos o cursor apontando para o início de Início do trecho (agora ele está na última posição).

Para isso, basta "retroceder o cursor", o que pode ser feito de vários jeitos. Vamos usar o comando C-b (de "backwards", "para trás"). Queremos retroceder 16 letras, o que pode ser feito com C-u 16 C-b.

Assim, a (longa) sequência de comandos que nos leva para o começo da próxima ocorrência (a letre "I") de "Início do trecho" é

  1. C-s Início do trecho C-u 16 C-b

(os únicos espaços que são digitados de fato circumdam o "do").

2 Movendo o trecho para um outro arquivo

O emacs permite que marcas sejam colocadas em pontos do texto. Quando uma marca é posta, as letras entre a posição da marca e a posição do cursor formam uma região.

Usaremos o comando C-w, que recorta (não no sentido usual — para mais informações, procure por "kill-region").

Para "matar" a região que vai ser escrita em outro arquivo, vamos

  1. Colocar uma marca no começo do trecho, usando o comando C-space (é pressionar a barra de espaços enquanto segura o Ctrl hein!)
  2. Ir para o fim do trecho: C-s Fim do trecho. (espaços apenas depois de "Fim" e antes de "Trecho".
  3. "Matar" o trecho: C-w

Queremos criar um novo arquivo, e colar (ou melhor dar um "yank") no trecho que está "recortado" (está no "kill ring"). Mas antes disso, vamos ver como fazer para saber qual o número do trecho.

O emacs tem um contador que pode ser usado justamente para nossos propósitos. É o kmacro-counter. Há vários comandos associados à manipulação desse contador (para saber que comandos estão associados ao contador, um jeito é usar o comando "apropos" M-x apropos). Aqui vamos usar os seguintes * M-x kmacro-set-counter para definir o valor inicial do contador * M-x kmacro-insert-counter para inserir o valor do contador (esse comando também incrementa o contador).

Com isso temos o que precisamos.

Juntando os pedaços

Neste ponto você já deve ser capaz de escrever a macro como um todo. Repetimos abaixo passo a passo o procedimento, com alguns comentários para relembrar o que estamos fazendo.

O primeiro trecho tem número 1.

  1. C-u 1 M-x kmacro-set-counter

Vamos agora definir a macro.

  1. C-x (

Buscamos o início

  1. C-s Início do trecho:

Posicionamos o cursor no início (voltamos 16 posições).

  1. C-u 16 C-b

Marcamos a posição corrente.

  1. C-space

Vamos para o fim do trecho.

  1. C-s Fim do trecho.

"Matamos" a região.

  1. C-w

Abrimos o arquivo trecho-X. Não há espaço entre "trecho-" e C-u no trecho abaixo! Note que usamos C-u 0 antes do comando para inserir o contador, para que o contador não seja incrementado ainda (lembre que ainda vamos usar o contador mais uma vez, no arquivo original). Note que se você estiver colocando os arquivos todos em alguma certa pasta diferente da atual, você pode trocar trecho- (na linha abaixo) por pasta-de-trechos/trecho- (assim os arquivos ficam nessa pasta).

  1. C-x C-f trecho- C-u 0 M-x kmacro-insert-counter

Agora que estamos no arquivo trecho-X, colocamos o trecho.

  1. C-y

Salvamos arquivo.

  1. C-x C-s

Fechamos o buffer (isso nos leva de volta ao arquivo que estava aberto antes).

  1. C-x C-k

Escrevemos a referência para o outro arquivo e inserimos o contador (dessa vez sem impedir o incremento). Note que não há espaço entre "trecho-" e M-x. Note também que há um ponto final depois de kmacro-insert-counter, para que fique: "Veja o arquivo trecho-X."

  1. Veja o arquivo trecho- M-x kmacro-insert-counter
  2. .

Finalmente, terminamos nossa macro.

  1. C-x )

Agora é só usar! Posicione o cursor no início do buffer e

  1. M-x call-last-kbd-macro

Ou, mais simplesmente, "C-x e" (se usar o segundo método, cada letra "e" que você pressionar após C-x e causa uma nova repetição da macro). Ainda mais, se você quiser que a macro seja executada por todo o arquivo, pode passar o argumento zero para o comando. Isso tem o efeito de fazer a macro ser executada até que algum de seus comandos não possa ser levado a cabo (uma busca falhou, o fim do buffer foi atingido, etc.).

Adendo

Há mais duas coisas que gostaria de falar antes de dar por encerrado o tutorial. Primeiro, você pode dar nomes à suas macros (para não ficar restrito a usar "a última macro definida"). Para fazer isso existe o comando M-x kmacro-name-last-macro. Se quiser ver os comandos de uma macro que tenha nome, existe o comando M-x insert-kbd-macro.

IMPORTANTE as macros não são guardadas se você não pedir explicitamente. Isso significa que se você fechar o emacs, ele esquece delas. Para que uma macro que você fez esteja sempre disponível, você precisa salvá-la em algum arquivo que o emacs leia ao abrir, como o .emacs.

O código abaixo, tomado do Emacswiki, define um comando que salva uma macro já nomeada.

  1. (defun save-macro (name)
  2. "save a macro. Take a name as argument
  3. and save the last defined macro under
  4. this name at the end of your .emacs"
  5. (interactive "SName of the macro :") ; ask for the name of the macro
  6. (kmacro-name-last-macro name) ; use this name for the macro
  7. (find-file (user-init-file)) ; open ~/.emacs or other user init file
  8. (goto-char (point-max)) ; go to the end of the .emacs
  9. (newline) ; insert a newline
  10. (insert-kbd-macro name) ; copy the macro
  11. (newline) ; insert a newline
  12. (switch-to-buffer nil)) ; return to the initial buffer

Esse código, claro, deve ser posto no seu arquivo .emacs.

Para usá-lo, defina uma macro, dê um nome para ela e então dê M-x save-macro para que ela esteja sempre disponível!

segunda coisa a comentar é que deixamos de lado uma questão importante. (Deixamos, na verdade, várias questões importantes de lado, mas a ideia aqui é só exemplificar um tipo de alteração que pode ser útil na macro.) O que fazer se já há arquivos de nome trecho-X? Um jeito de nos prevenirmos contra uma indesejada corrupção no conteúdo de arquivos que estavam inocentemente no caminho de nossa macro-fúria, é abortar a operação (antes de matar o trecho), e imprimir uma mensagem de aviso. Para isso talvez uma macro não seja a melhor escolha. Penso que uma função (como a save-macro) deva ser mais adequada.

Dito isso, bom proveito!

Referências

Várias vezes precisei recorrer ao já citado emacswiki, ao stackoverflow e ao Emacs Lisp reference Manual (Emacs Lisp é a linguagem de programação que pode ser usada no emacs).

 

Não há comentários.

Comentar