Respostas:
Em cima da minha cabeça, o comando mais próximo é o M-z "
que apaga tudo, do ponto até a próxima ocorrência do personagem ".
Também existe C-M-k
, também conhecido como "matar expressão equilibrada", que excluirá uma declaração entre parênteses completa ou cadeia de caracteres com aspas duplas, etc. com base na definição atual dos modos de "expressão equilibrada" e no caractere atualmente em questão (isto é, só funciona se o cursor está na abertura '"' ou '(' etc.).
Da mesma forma que a sugestão de Justin, o CM-SPACE fornece "mark-sexp", que seleciona o ponto de equilíbrio, a citação etc., e então você pode Cw ou qualquer outra coisa para fazê-lo desaparecer. Caso você queira VER o que está prestes a excluir antes de excluí-lo ...
Sim! O equivalente ao comando VIMs ci "no Emacs é ... ci" :-)
http://www.emacswiki.org/emacs-de/Vimpulse
Apenas tropeçou nessa questão; aqui está uma solução personalizada que funcionou para mim:
(defun seek-backward-to-char (chr)
"Seek backwards to a character"
(interactive "cSeek back to char: ")
(while (not (= (char-after) chr))
(forward-char -1)))
(defun delete-between-pair (char)
"Delete in between the given pair"
(interactive "cDelete between char: ")
(seek-backward-to-char char)
(forward-char 1)
(zap-to-char 1 char)
(insert char)
(forward-char -1))
Em seguida, vincule excluir entre pares a qualquer tecla que desejar. Para mim, eu tenho isso ligado a Cz i.
Receio não conhecer o recurso ci do VIM, mas você já viu o Emacs regexp substituir? Não posso falar com a semântica exata ou com o quão fácil é usar em comparação, mas é o que eu usaria para o que acho que você deseja.
Magnars (autor do site EmacsRocks) escreveu este plugin para fazer exatamente o que você está pedindo.
https://github.com/magnars/change-inner.el
Obviamente, você também pode usar o modo Evil.
Aqui está minha versão que excluirá tudo dentro (ou incluindo) de um par de caracteres correspondente. Os pares de caracteres são definidos em uma lista para que o caractere inicial / final correspondente seja conhecido. Eu mapeei para "Cc i" para alterar e "Cc a" para alterar todos.
Ele também copia os caracteres removidos para a área de transferência para colar posteriormente.
; Re-create ci" ca"...
(defun seek-backward-to-char (chr)
"Seek backwards to a character"
(interactive "cSeek back to char: ")
(while (not (= (char-after) chr))
(forward-char -1)))
(setq char-pairs
'(( ?\" . ?\" )
( ?\' . ?\' )
( ?\( . ?\) )
( ?\[ . ?\] )
( ?\{ . ?\} )
( ?< . ?> )))
(defun get-char-pair (chr)
(let ((result ()))
(dolist (x char-pairs)
(setq start (car x))
(setq end (cdr x))
(when (or (= chr start) (= chr end))
(setq result x)))
result))
(defun get-start-char (chr)
(car (get-char-pair chr)))
(defun get-end-char (chr)
(cdr (get-char-pair chr)))
(defun seek-to-matching-char (start end count)
(while (> count 0)
(if (= (following-char) end)
(setq count (- count 1))
(if (= (following-char) start)
(setq count (+ count 1))))
(forward-char 1)))
(defun seek-backward-to-matching-char (start end count)
(if (= (following-char) end)
(forward-char -1))
(while (> count 0)
(if (= (following-char) start)
(setq count (- count 1))
(if (= (following-char) end)
(setq count (+ count 1))))
(if (> count 0)
(forward-char -1))))
(defun delete-between-pair (char)
"Delete in between the given pair"
(interactive "cDelete between char: ")
(seek-backward-to-matching-char (get-start-char char) (get-end-char char) 1)
(forward-char 1)
(setq mark (point))
(seek-to-matching-char (get-start-char char) (get-end-char char) 1)
(forward-char -1)
(kill-region mark (point)))
(defun delete-all-pair (char)
"Delete in between the given pair and the characters"
(interactive "cDelete all char: ")
(seek-backward-to-matching-char (get-start-char char) (get-end-char char) 1)
(setq mark (point))
(forward-char 1)
(seek-to-matching-char (get-start-char char) (get-end-char char) 1)
(kill-region mark (point)))
(global-set-key (kbd "C-c i") 'delete-between-pair)
(global-set-key (kbd "C-c a") 'delete-all-pair)
Isso era algo que estava faltando no Vim, e zap-to-char
não parecia acertar.
Aqui está minha humilde tentativa de recriar "ci" e "ca":
(defun change-outer (str)
(interactive "sChange outer: ")
(condition-case nil
(search-backward str (line-beginning-position))
(error (search-forward str (line-end-position))
(forward-char -1)))
(kill-sexp)
)
(defun change-inner (str)
(interactive "sChange inner: ")
(condition-case nil
(search-backward str (line-beginning-position))
(error (search-forward str (line-end-position))
(forward-char -1)))
(push-mark)
(forward-sexp)
(forward-char -1)
(exchange-point-and-mark)
(forward-char 1)
(kill-region (point) (mark))
)
Normalmente, o caso de condição não é necessário, uma vez que o terceiro parâmetro (opcional) de pesquisa para frente / pesquisa para trás serve para indicar o que fazer caso a pesquisa falhe. Mas, por alguma razão, colocar a segunda pesquisa como o terceiro parâmetro para a primeira gera um comportamento estranho.
Eu tentei as soluções aqui, mas achei que cada uma delas estava querendo de alguma forma, então eu vim com isso. Ele aceita um delimitador inicial ou final e usa funções internas do Emacs para evitar a necessidade de uma tabela de conversão para delimitadores.
(defun change-inner (prefix character)
"Kill region inside delimiters, using either beginning or
ending delimiter. With prefix arg, kill including delimiters."
(interactive "p\nc")
(let ((initial-point (point))
(start)
(end)
(move-point-by (if (> prefix 1) 0 1)))
(condition-case nil
(progn
;; Search forward for given char
(search-forward (char-to-string character))
(setq end (- (point) move-point-by))
(condition-case nil
(backward-sexp)
(error (backward-list)))
(setq start (+ (point) move-point-by))
(kill-region start end)
(or prefix (forward-char)))
(error (progn
;; Reset and search backward for given char
(goto-char initial-point)
(search-backward (char-to-string character))
(setq start (+ (point) move-point-by))
(condition-case nil
(forward-list)
(error (forward-sexp))))
(setq end (- (point) move-point-by))
(kill-region start end)
(or prefix (backward-char))))))
(global-set-key (kbd "M-i") 'change-inner)
(defun change-outer ()
(interactive)
(let ((current-prefix-arg '(4)))
(call-interactively 'change-inner)))
(global-set-key (kbd "M-o") 'change-outer)