(replace-string "o" "ô") substitui a próxima ocorrência de o após o cursor¹, exceto no modo de marca transitória com uma marca ativa, caso em que substitui a primeira ocorrência na região marcada.
Isso funciona para substituir o caractere após o cursor, mas, claro, se isso não for um o , ele poderá substituir um caractere adicional. Você poderia usar os argumentos START e END para replace-string para limitar a extensão da substituição, mas isso não será escalável. Use char-after para recuperar o caractere após o cursor e char-before para recuperar o caractere antes do cursor. Esta função parece destinada a ser usada depois de digitar um o , então acho que char-before é o que você está procurando.
(require 'cl)
(defun thai-add-tone ()
(interactive "*")
(case (char-before)
((?o)
(delete-backward-char 1)
(insert "ô"))
((?u)
(delete-backward-char 1)
(insert "û"))))
Uma abordagem alternativa é fazer um teste (ou uma série de testes) com looking-at (para texto que começa no cursor) ou looking-back (para o texto que termina no cursor). Você pode, então, chamar replace-match para substitua o texto; isso permite alguma automação, por exemplo, o Emacs pode cuidar da substituição de letras minúsculas por letras minúsculas e maiúsculas por letras maiúsculas.
(defvar thai-tone-conversion-list
'(("o" . "ô") ("u" . "û")))
(defun thai-add-tone ()
(interactive "*")
(when (let ((case-fold-search t))
(looking-back "[ou]"))
(replace-match (cdr (assoc (match-string 0) thai-tone-conversion-list)))))
Note que o Emacs já tem algum suporte para o tailandês, pode ser mais fácil construir sobre ele do que reinventar a roda. Você pode selecionar um dos dois métodos de entrada tailandeses com set-input-method ( C-x RET C-\ ). Não parece haver nenhuma documentação em inglês além do código-fonte .
¹ Na terminologia do Emacs, o “cursor” como na posição em que as edições são feitas é chamado de ponto . A palavra cursor é reservada para o artefato visual na tela que marca a posição do ponto.