Para adicionar um pouco de fogo na velha “editor wars”, eu resolvi testar o SublimeText, Zed, e o Atom.

Antes, um disclaimer: eu sou um usuário VIM. Não um super usuário VIM – eu, por exemplo, uso as setas para navegar dentro de um arquivo (oh, o horror!), uso poucos plugins, enfim. Aí resolvi testar o SublimeText, e achei ele fantástico – rápido, estável, e funciona bem. Só tem um problema: 70 dólares.

Eu acho válido pagar por algo que você vai usar todos os dias. Mas 70 dólares é 1/3 de um Office. Já que eu tinha alternativas, resolvi testar o Atom. Antes disso, eu tinha feito um plugin para o Sublime, para rodar coisas pelo TMUX, e resolvi portar o mesmo aplicativo para o Atom, como um exemplo.

O Atom usa tecnologias web – HTML + CSS + JS + Node.JS para funcionar. Basicamente, plugins (e customizações do Atom) são escritos em Coffeescript ou Javascript, usando Node.JS, toda a interface do Atom, incluindo menus, abas, telas, são feitas usando HTML + CSS, você pode re-estilizar a tela toda usando LESS ou CSS, e os arquivos de config são em CSON ou JSON. O ponto negativo disso é que basicamente o Atom consome tanto de memória como o Chrome / Chromium, já que na verdade, ele basicamente É a mesma coisa – um browser rodando uma página. Há muitas vantagens na abordagem do Atom – a tela inteira do seu editor é customizável.

O veredicto final eu achei bom: eu acabei gostando do Atom. Ele é um pouco mais lento do que eu gostaria, e consome uns 300 – 400mb de memória na minha máquina (o que é bem ruim na verdade para pessoas que tem máquinas com pouca RAM) . Outra coisa que é perceptível é a facilidade de se fazer plugins (há um “scaffolding” de plugins no Atom) e quão fácil é integrar dependências externas, testes dos próprios plugins, etc. O ponto baixo sempre será o consumo de memória e de disco, que o Atom simplesmente precisa melhorar – e muito.

Sobre cada um dos detalhes:

Primeira barreira: Javascript

Eu não sou um fã de Javascript, na verdade. Nem de Coffeescript. Se fosse para optar, eu usaria o Python que o Sublime usa para fazer pacotes, porém o atom integra tão bem o coffeescript que pareceu uma ótima idéia. É fantástico usar o Node.JS para fazer plugins, já que ele naturalmente é assíncrono – nada de editor travando, nada de problemas com sincronismo de threads e mutexes.

Um outro ponto a se pensar é que o Atom é apenas um editor – eu não preciso deixar o JS genérico para rodar em vários browsers. Além disso, ele é bem customizado para usar Coffeescript, o que já facilita bastante o desenvolvimento.

Quando consegui quebrar essa barreira, tudo ficou bem mais fácil. Além do mais, dá pra um plugin “saber da existência” do outro, usando providers. Isso foi bem interessante, e eu uso no meu plugin Everything e no meu plugin Rails-I18n.

VIM-Mode

Não vamos nos enganar: o suporte para o VIM usando o plugin vim-mode não é bom. Não suporta block editor (estou tentando dar um jeito nisso fazendo um plugin chamado motion), o “change inner” não funciona direito, e o “visual mode” não funciona com home, end, Page Up ou Page Down. Provavelmente não deveria funcionar mesmo, mas ainda assim era uma idéia legal a se ter…

Para contornar esse problema, eu usei uma série de key-bindings para fazer o que eu queria. Basicamente, tentei deixar o autocomplete do VIM, e uma série de outros exemplos, bem mais amigáveis. O plugin vim-mode adiciona uma classe ao editor, permitindo assim que se registrem keybindings apenas em situações específicas – por exemplo, dentro do modo de comando, apertar CRTL+P é diferente de quando se apertar essa tela no modo de inserção. Logo, abaixo estão meus keybindings pro VIM funcionar do jeito que eu queria:

'.vim-mode':
  'ctrl-right': 'vim-mode:move-to-next-word'
  'ctrl-left': 'vim-mode:move-to-previous-word'

'.vim-mode.insert-mode':
  'ctrl-p': 'autocomplete-plus:activate'
  'end': 'editor:move-to-end-of-screen-line'

'.vim-mode.visual-mode':
  'home': 'vim-mode:move-to-beginning-of-line'
  'end': 'vim-mode:move-to-last-character-of-line'
  'pageup': 'vim-mode:scroll-full-screen-up'
  'pagedown': 'vim-mode:scroll-full-screen-down'
  'ctrl-home': 'vim-mode:move-to-start-of-file'
  'ctrl-end': 'vim-mode:move-to-line'

'atom-text-editor.vim-mode.command-mode':
  'shift-z shift-z': 'vim-mode:zz'
  'ctrl-v': 'block-selection-mode:toggle'
  'ctrl-\\': 'symbols-view:go-to-declaration'
  '?': 'ex-mode:open'
  'ctrl-c': 'tmux-terminal:send-break'
  'ctrl-o': 'last-cursor-position:previous'
  'end': 'vim-mode:move-to-last-character-of-line'

'atom-text-editor.vim-mode.insert-mode':
  'ctrl-p': 'autocomplete-plus:activate'

Há outras coisas para o vim ficar legal. Uma delas foi mapear o “?” para o ex mode (já que, por algum motivo, quando resolve keybindings o Atom não leva em consideração qual o teclado que você está usando). Outra foi criar alguns comandos e mapeá-los para o ex mode (já que certas coisas, como “ZZ” não funcionam, e outras como “q!” também não – te pedem pra salvar). Mapeei o “qq” para o “q!”, porque por hora, o ex-mode não te permite mapear “q!” ou qualquer keybinding que usa exclamação no final. Adicionei as linhas no meu init script:

atom.commands.add 'atom-workspace', 'vim-mode:zz', ->
  pane = atom.workspace.getActivePaneItem()
  if pane.isModified()
    if pane.getPath()
      pane.save()
      pane.destroy()
    else
      alert('No file name')
  else
    pane.destroy()

atom.packages.onDidActivatePackage (pack) ->
  if pack.name == 'ex-mode'
    Ex = pack.mainModule.provideEx()
    Ex.registerCommand 'q', ->
      pane = atom.workspace.getActivePaneItem()
      if pane.isModified()
        alert("No write since last change")
      else
        pane.destroy()

    Ex.registerCommand 'qq', ->
      atom.workspace.getActivePaneItem().destroy()

Isso deixou meu vim-mode bem aceitável.

Bugs no Atom

Há um problema sério com alguns bugs. Por rodar numa sandbox, há algumas coisas que são meio incompreensíveis – certas chamadas de métodos dão alguns problemas, se você chama um “shell” que usa suid flag (como por exemplo, subir uma máquina do VirtualBox ou até do Vagrant, às vezes) isso dá problema. O maior problema, porém, para mim, é quando se abre uma URL – se você usa o Google Chrome (como eu) isso trava seu editor. Péssimo. Eu fiz um hack para resolver isso também – basicamente, um monkey-patch numa classe:

shell = require 'shell'
shell.openExternal = (url) -> child.spawn('google-chrome', ['--no-sandbox', url])

Outros problemas é quando se abre um projeto que tem dependências em submodules no Github, o plugin do Github não funciona direito. Corrigi isso também com alguns comandos simples:

atom.commands.add 'atom-workspace', 'github:open-project-page', ->
  shell.openExternal findGithubRepository()

atom.commands.add 'atom-workspace', 'github:open-pull-requests', ->
  shell.openExternal findGithubRepository() + "/pulls"

atom.commands.add 'atom-workspace', 'github:create-pull-request', ->
  fileName = atom.workspace.getActiveTextEditor().getPath()
  branch = child.spawnSync('git', ['status'], cwd: path.dirname(fileName))
    .stdout.toString().split("\n")[0].replace(/on branch (.*).*/i, "$1")
  shell.openExternal findGithubRepository() + "/pull/new/" + branch

findGithubRepository = ->
  fileName = atom.workspace.getActiveTextEditor().getPath()
  out = child.spawnSync('git', ['remote', '-v'], {cwd: path.dirname(fileName)})
  repo = out.stdout.toString().split("\n").filter((row) -> row.match(/origin.*push/))[0]
  "https://" + repo.split(/@|\s/)[2].replace(':', '/').replace(".git", "")

Pacotes

Eu tento depender pouco de plugins, mas às vezes é meio inevitável. Eu optei pelos seguintes pacotes no Atom:

  • Motepair para pair programming
  • atom-beautify porque às vezes eu tenho que debugar SQLs gigantescas, e é bom algo que indente-as para mim
  • everything, um pacote meu não-publicado aonde eu quero deixar todos os comandos do ATOM, junto com um set syntax, I18n do rails, busca do google e outras coisas todas num mesmo lugar para serem buscadas
  • ex-mode é um complemento do vim-mode
  • git-tab-status um pacote simples que deixa a aba colorida quando algum arquivo que eu estou editando não está versionado, ou está diferente do repositório
  • last-cursor-position para usar com o vim-mode, como um “GOTO BACK”. Não funciona 100% do jeito que eu queria, mas já é um começo
  • motion é um plugin meu ainda não publicado, que tenta melhorar a seleção de múltiplos cursores, selecionar dentro de aspas, parênteses, regexp, entre outras coisas
  • tmux-terminal um pacote meu ainda não publicado, para rodar comandos no TMUX
  • rails-i18n um pacote meu ainda não publicado (que integra com o everything) que permite buscar elementos I18n do Rails e entrar direto no arquivo de tradução
  • set-syntax um pacote (que eu espero torná-lo obsoleto em breve, para integrar com o Everything) que coloca no command-palette um comando para setar a sintaxe do arquivo atual
  • symbol-gen gera os símbolos (métodos, classes, funções) do projeto atual
  • symbols-tree-view uma visualização em árvore dos símbolos do projeto atual
  • vim-mode permite navegação tipo VIM no Atom

Considerações finais

Eu gosto do VIM. Realmente gosto. Se eu pudesse escolher, eu preferiria a edição, rapidez, poder de alteração de arquivos do VIM. Porém, ultimamente eu sinto que ele é meio insustentável.

São muitos comandos para lembrar, muitas teclas de atalho para mapear. Muitas coisas parecem “half-baked”, como por exemplo, o NERDTree – ele parece uma tela, mas não é. Parece um texto, mas não é. Fica só numa aba, mas respeita os splits. Ele não consegue perceber alterações no diretório ou nos arquivos automaticamente, e praticamente tudo o que se faz nele deve ser feito manualmente.

Ele tem poder, de verdade, mas é difícil de achar plugins que realmente integrem. Ou melhor dizendo, os plugins integram justamente porque o VIM não é, ele só, integrado – tudo é feito usando splits, tabs, etc.

No mundo do ATOM, as coisas são mais simples: comandos tem nomes que podem ser buscados, fazer plugins é simples e o plugin aceita testes automatizados, é possível usar uma API bacana para integrar com o editor, dá pra fazer “layers”, enfim… tudo fica relativamente mais simples.

O ponto negativo, ainda assim, é o consumo de memória e o tamanho do Atom – com plugins, ele pode facilmente virar um Eclipse de tão grande. Eu já senti isso quando tentei fazer um “atom-dotfiles” no github, e hoje em dia eu não saberia como fazer isso ainda. Porém, a flexibilidade do editor (e da idéia de usar HTML + CSS + JS) dá uma customização tão absurda que, para mim está compensando.