Correction de DOpble CApitals pendant que je tape

23

J'ai un petit rose lent. Alors que mes autres doigts deviennent de plus en plus rapides à taper, mon petit doigt ne peut tout simplement pas suivre. Cela m'amène fréquemment à taper des phrases dont le premier mot commence par deux lettres majuscules. Voici un petit exemple.

THere's nothing in there. DEfinitely not a body.

Habituellement, ce que je fais est touché M-b M-c(en supposant que je le repère immédiatement), mais je m'en lasse un peu.

Comment puis-je demander à Emacs de résoudre ce problème automatiquement pour moi?

C'est-à-dire que j'aimerais qu'Emacs détecte lorsque je tape un mot qui commence par deux lettres majuscules suivies d'au moins une lettre minuscule, et corrige cela automatiquement.

Malabarba
la source

Réponses:

19

Voici une fonction qui convertira les CApitaux DOubles en capitales simples. J'avais initialement suggéré de l'ajouter à post-self-insert-hook, mais ci-dessous est une option pour un mode mineur glorifié afin que vous n'ajoutiez à ce crochet que lorsque vous le voulez vraiment:

(defun dcaps-to-scaps ()
  "Convert word in DOuble CApitals to Single Capitals."
  (interactive)
  (and (= ?w (char-syntax (char-before)))
       (save-excursion
         (and (if (called-interactively-p)
                  (skip-syntax-backward "w")
                (= -3 (skip-syntax-backward "w")))
              (let (case-fold-search)
                (looking-at "\\b[[:upper:]]\\{2\\}[[:lower:]]"))
              (capitalize-word 1)))))

(add-hook 'post-self-insert-hook #'dcaps-to-scaps nil 'local)

Et la définition du mode mineur:

(define-minor-mode dubcaps-mode
  "Toggle `dubcaps-mode'.  Converts words in DOuble CApitals to
Single Capitals as you type."
  :init-value nil
  :lighter (" DC")
  (if dubcaps-mode
      (add-hook 'post-self-insert-hook #'dcaps-to-scaps nil 'local)
    (remove-hook 'post-self-insert-hook #'dcaps-to-scaps 'local)))

Pour ce que ça vaut, en utilisant cette version:

  • est simple: il suffit de l'activer / le désactiver manuellement ou en mode hook;
  • ne nécessite aucune modification des raccourcis clavier, vous ne perdez donc aucune autre fonctionnalité.

Même lorsque vous l'ajoutez à post-self-insert-hook, les frais généraux sont presque inexistants, du moins selon certains tests de référence simples. Sur ma machine, voici ce que j'obtiens avec 10 000 répétitions chacune d'une forme ridiculement simple et la dcaps-to-scapsfonction:

(benchmark-run-compiled 10000 (+ 1 1))          ; => .001 to .003 -ish
(benchmark-run-compiled 10000 (dcaps-to-scaps)) ; => .003 to .006 -ish

Donc, oui, c'est plus lent que d'ajouter 1 + 1, mais en termes absolus, vous ne le remarquerez jamais.

Dan
la source
Vous pouvez utiliser looking-at-p, qui ne définit pas du tout les données de correspondance (c'est correct car vous n'en avez pas besoin ou ne les utilisez pas ici).
YoungFrog
Quelques remarques supplémentaires , la plupart du temps sans importance (mais je préfère votre réponse donc je veux contribuer, p): l'utilisation de forward-wordne fonctionnent pas bien avec subword-mode, en utilisant (char-syntax (char-before))va (je suppose) ignorer un ensemble de classe de syntaxe avec des propriétés (solution alternative: (syntax-after (1- (point))) , et (last but not least) l'expression rationnelle ne trouvera pas de lettres accentuées (par exemple "ÉMincer", en français)
YoungFrog
@YoungFrog: mise à jour pour traiter le forward-wordproblème et modification de l'expression rationnelle pour traiter les majuscules accentuées.
Dan
Y at - il une raison de préférer andplus when, notamment en premier lieu?
Clément
@ Clément: andest court-circuité, donc la logique fonctionne comme whenici. Je ne sais pas s'il existe des meilleures pratiques concernant l'utilisation de l'un par rapport à l'autre, mais il semble que cela poserait une bonne question sur ce site (je voterais de toute façon).
Dan
8

Ma préférence est de simplement créer une nouvelle fonction qui fait ce que l'habituel self-insert-commandferait en plus .

Voici quelques raisons:

  • Contrôle plus fin sur les principaux modes qui devraient avoir cette capacité de correction automatique. Pour ce cas d'utilisation, il pourrait être mode texte uniquement comme org-mode, text-mode, etc.
  • Pour le type de correction demandé dans la question, l'utilisateur doit généralement appuyer sur SPCou RETou sur la .touche après le mot. Donc, utiliser quelque chose comme ça post-self-insert-hookpourrait être une exagération, et nous ferions ce traitement supplémentaire chaque fois que vous appuyez sur une touche.

Ainsi, la solution proposée ci-dessous lie cette fonction avec juste la SPCclé org-mode-map(en ignorant le cas du coin où le mot pourrait être le dernier mot d'une ligne). Si nécessaire, l'utilisateur peut lier des fonctions d'encapsuleur similaires à plusieurs clés.

(defun space-plus-more ()
  (interactive)
  (save-excursion
    (backward-word 1)
    (let ((case-fold-search))
      (when (looking-at-p "[A-Z]\\{2\\}.*?[a-z]+.*?\\b")
        (capitalize-word 1))))
  (self-insert-command 1))

(define-key org-mode-map (kbd "<SPC>") #'space-plus-more)

Ceci est un exercice elisp intéressant :)

Personnellement, je ne voudrais pas y lier RETcar je perdrais alors les liaisons par défaut org-modeet probablement d'autres modes majeurs. Mais c'était intéressant d'en apprendre davantage sur eltet this-command-keys-vector.

(defun my/fix-double-caps ()
  (interactive)
  (save-excursion
    (backward-word 1)
    (let ((case-fold-search))
      (when (looking-at-p "[A-Z]\\{2\\}.*?[a-z]+.*?\\b")
        (capitalize-word 1))))
  (if (eq 13 (elt (this-command-keys-vector) 0)) ; detect RET
      (newline)
    (self-insert-command 1)))

(let ((maps-list (list org-mode-map
                       text-mode-map))
      (keys-list (list "<SPC>" "<RET>" ".")))
  (dolist (map maps-list)
    (dolist (key keys-list)
      (define-key map (kbd key) #'my/fix-double-caps))))
Kaushal Modi
la source
Oh oui, le limiter aux modes dérivés du texte est certainement une bonne idée. :)
Malabarba
@Malabarba ne voulez-vous pas ce comportement dans les chaînes pour les modes dérivés de prog-mode?
YoungFrog
@YoungFrog bien sûr, mais il faudrait alors vérifier qu'il se trouve bien dans une chaîne, sinon il se mettrait juste en travers du chemin.
Malabarba
0

Peut-être que cette réponse ne fournit pas la solution que vous attendez (correction interactive des mots pendant que vous tapez), je voudrais partager mes façons de lutter contre de tels problèmes.

Tout d'abord, je n'aime pas les choses qui changent silencieusement mon texte (en majuscule, etc., si vous voulez taper le mot IBuffer, je pense qu'un tel "correcteur" est une mauvaise façon), donc je conseille deux choses:

Tout d'abord, essayez d'activer la fonction "Sticky Keys". Cela peut sembler bizarre au premier abord mais je l'utilise tout le temps. Cette fonctionnalité est disponible au niveau de l'environnement OS / bureau, ce n'est pas un truc Emacs. Lorsque cette chose est activée, vous appuyez d'abord sur ⇧ Shiftpuis vous appuyez sur une autre touche que vous souhaitez mettre en majuscule. De cette façon, votre problème ne peut même pas se poser, une seule lettre est capitalisée dans cette approche séquentielle! Cela réduit également le travail que vos mains doivent faire pour maintenir la ⇧ Shiftclé. Je pense qu'il est plus facile de taper maintenant.

Deuxièmement, maintenant vous pouvez toujours utiliser la ⇧ Shiftclé normalement (en la maintenant) lorsque vous pensez que c'est nécessaire, mais je voudrais vous proposer un package Emacs appelé Fix Word . Même si vous n'aimez pas les «touches rémanentes», vous pouvez facilement corriger les mots dans leur forme appropriée, et vous pouvez corriger plusieurs mots d'affilée sans mouvements inutiles du curseur. Essayez-le, je l'utilise tout le temps. (Il est toujours difficile de corriger les choses si vous avez entré plusieurs mots et que le mot que vous devez mettre en majuscule se trouve quelque part au milieu.)

Mark Karpov
la source