Vim Language Server Client (LSC) plugin first impressions

After months of problems with CoC: https://github.com/neoclide/coc-eslint/issues/72 I’ve given up and I’m trying other plugins.

I used ALE for ages with eslint, but never got it decently working using LSP. I tried ALE with Deoplete – but ALE is very slow and deoplete took ages to configure (python3 + pip + msgpack 1.0+ is a pain to install).

I came across this blog post showing love for Language Server Client (LSC): https://bluz71.github.io/2019/10/16/lsp-in-vim-with-the-lsc-plugin.html.

But this had a problem that it doesn’t work for linting, only LSP and I need eslint.

However this reddit comment described perfectly the use of installing ALE and LSC.

ALE with eslint, LSC with tsserver (+ LSP compliant wrapper typescript-language-server).

This seems like a good combo. ALE was reliable for ages and slow linting doesn’t matter too much, it’s slow auto-completion that’s a problem. Also ALE doesn’t have the floating window features that CoC and LSC do.

LSC along with ALE is almost entirely Vimscript (with some Dart that doesn’t require a further install) which makes it an easy install – no further dependencies makes plugins much better with Vim.

Installation of raw plugin

First thing that disappoints me currently in the instructions of the plugin is not having the Plugin code to copy-paste, I love where I can blindly follow the instructions with copy paste and it all magically works.

So to install the plugin in your .vimrc or init.nvim for example using Plug or Vundle:

Plug

Plug 'natebosch/vim-lsc'

Then run :PlugInstall

Vundle

Plugin 'natebosch/vim-lsc'

Then run :PluginInstall

Pathogen

git clone https://github.com/natebosch/vim-lsc ~/.vim/bundle/vim-lsc

Then run :Helptags to generate help tags

Dein

call dein#add('natebosch/vim-lsc')

This will work too with any of the other plugin managers that support github plugins as sources.

Installation of typescript language server

However at this point you have a problem because there is nothing to indicate that anything is working. No auto-completion happens, nothing.

If you install Coc, from what I remember immediately auto-completion starts happening.

You can run :LSC<tab> which should open up a list of the possible LSC commands to at least show that you have it installed.

Coc starts working for pretty much every file with an auto-complete using the words in the current file. This is great for seeing the immediate response that you know you’ve installed the plugin correctly. Plus with Coc you can run :CocInstall coc-eslint which starts installing the eslint and then works again immediately from what I remember.

I want to test LSC with the typescript LSP, which I’d already installed with:

npm install --global typescript

Now fair enough but rather frustratingly the typescript tsserver isn’t a fully compliant LSP, so you need the LSP compliant wrapper typescript-language-server mentioned above install globally same as typescript:

npm install --global typescript-language-server

I have two specific requirements which makes my commands differ:

  1. I use yarn
  2. I installed yarn/npm using sudo

So my actual command was:

sudo yarn global add typescript typescript-language-server

Coc mimics VS Code and works with tsserver out of the box which saves you from having to install the extra library. If LSC could be made to work with tsserver it would be a nice step. Coc even goes so far as to install tsserver for you so you just need CocInstall coc-tsserver and the magic starts happening. So you can install and get Coc working without having to leave Vim – the same happens for eslint because typically developers using eslint will already have it in their project and this just gets picked up magically.

The frustration of typescript-language-server is that there is the far too similarly named javascript-typescript-langserver, I have no idea of the difference nor do I really care, I just want the one that works. The LSC documentation for JavaScript language servers fails for this it shows me how to configure both of them but gives me no idea which one I should prefer.

I’m very much a proponent for the “don’t make me think” mantra because that’s what most people are after when they’re trying to install a plugin.

Why go through all the work of writing your plugin in Vimscript only to leave the documentation bare leaving people frustrated.

Configuration

Annoyingly the configuration for Javascript is buried. There’s no mention in the README that there is a wiki that lists all the language server configurations, and even in the wiki the home page is bare, so you have to spot the pages menu on the left-hand side.

Then when you get to the Javascript section you have the previously mentioned problem that there are two servers and you don’t know which to choose.

So I already have tsserver installed and that’s used by VS Code and so is used by 90% of all developers now and so I’ll use that.

let g:lsc_server_commands = {
  \ 'javascript': 'typescript-language-server --stdio'
  \ }

Futher frustration though is that there’s no comments in there giving helpful tips on how to set them up properly. The bluz71 blog above has the useful extra hint:

For LSC to function please ensure typescript-language-server is available in your $PATH.

So you should make sure to add the npm/yarn global installation directory into your path – it’s easy enough to find instructions for this. To test make sure you can run this in the directory where you start Vim:

$ typescript-language-server --version
0.4.0

Obviously you’ll probably get some other version number, but you should at least get a response. You don’t set up a path to the language server binary in the config so it assumes you’ve got it directly available.

That’s all folks… not quite

That should be that. With a restart of Vim the magic should happen – open up a Javascript file, start typing away and BAM, auto-complete pop-ups should start appearing.

However for me it didn’t, patiently typing a few characters and then reading documentation on how many characters to type before something happened did nothing.

I tried a :LSClientGoToDefinition and it spewed out an error:

Error detected while processing function lsc#reference#goToDefinition[2]..lsc#server#userCall:
line    2:
E684: list index out of range: 0
E15: Invalid expression: lsc#server#forFileType(&filetype)[0]

Firstly getting errors is always bad and secondly this error message makes no sense.

The problem here is that there is no ‘health check’ that I could find. ALE gives a very good diagnostics page via :ALEInfo. The LSClientAllDiagnostics and :LSClientWindowDiagnostics that sound like they might be useful aren’t at all in this situation.

Even after reading through :help lsc I did not spot anything to help with spotting issues. But the intro there is very helpful:

There is no install step for vim-lsc. Configure the filetypes that are tracked
by installed language servers in the variable “g:lsc_server_commands”. Each
value in this dict should be a string which corresponds to either an
executable in your “$PATH”, an absolute path to an executable, or a
“host:port” pair. If multiple filetypes are tracked by the same server they
should be entered as separate keys with the same value. The value may also be
a dict to allow for additional configuration.

It was only after re-reading the bluz71 blog again that I spotted my problem:

For a given filetype the LSC plugin will take care of launching, communicating and shutting down the named language server command.

My problem is that because I have the mxw/vim-jsx plugin, my javascript filetype becomes javascript.jsx, so my config needs:

let g:lsc_server_commands = {
  \ 'javascript.jsx': 'typescript-language-server --stdio'
  \ }

Now I did a re-source of my .vimrc via :source % and then tried again with my Javascript file and nothing worked still.

However doing a restart of Vim, now I got an error that flashed up in the Vim command line and disappeared, but then finally the magic started to happen.

So to know if LSC is working, the first thing you notice is that it subtly highlights the word you are on and any other words (‘symbols’) that match that.

Now auto-completion starts working and I can tweak away with key mappings. However I don’t really care about key mappings – they’re easy to tweak.

Final thoughts

This does seem like a great plugin now that it’s working. It has the speed and functionality of Coc and it works which is a major plus point over Coc at the moment.

What I fundamentally care about when trying these LSP plugins is getting something to work as fast as possible so I can test out the plugin. I can then add other language servers and configurations, but until I’ve got something working there’s nothing but frustration.

Translating WordPress plugins

If you didn’t write the plugin – how do you translate it? I found lots of information for plugin developers to make their plugins translatable but not for people that just want to translate it.

Executive summary / tl;dr

Edit: The Codestyling Localization plugin I suggested previously isn’t available from WordPress directly any more.

Instead there seems to be an equally good plugin Loco Translate that is complemented by the developers own site for translating any application.

Failing that try the ‘Blank WordPress POT’ with POEdit and put that in the plugin’s languages directory. This seems to be a rock solid approach but takes a bit of learning.

If you put your translations in the plugins language directory, you’ll lose your translations when the plugin gets updated. Either keep backups or, if the plugin loads the translations correctly, you can put your translations in the separate wp-content/languages/[plugin-name] directory.

For worker ants who want to know a bit more

  1. The plugin must be translatable (It has been internationalized)
  2. You can check this by looking through the plugin code
  3. Otherwise just carry on and hope that the developer made it translatable
  4. Then you need to create a translation file that converts the English words into your language (localize it)
  5. A POT (.pot) file is a skeleton file that contains all the words and phrases in the plugin that can be translated
  6. A .po file is a .pot file that has had the translated strings in your language added next to each of the translatable phrases
  7. When you save a .po file it also generates a .mo file (where as you can read a .po file in notepad you can’t read a .mo file)
  8. WordPress plugins rely on .mo files
  9. You first need to find the .pot file
  10. Typically this will be in the root of the plugin directory
  11. Or it will be in a languages directory
  12. If you find it, great. Open it in POEdit, do your stuff and save
  13. If it hasn’t been created at all …
  14. … Then you need to check in the code (look for load_plugin_textdomain in the main plugin file) to see where/if you should create one and create the .pot file yourself

If you don’t know about editing PO files I suggest following the WordPress instructions on using POEdit.

For developers to ‘internationalize’ their plugins

I recommend using the Blank WordPress POT file that I mention below in the POEdit revisited section.

Translation fumbling

POEdit

Initially I tried the POEdit method recommended in WPMU DEV tutorial

However the POT files that I made never worked – they didn’t pick up the translated words. I think it was because of __() and _e() instead of __ and _e.

makepot.php

  • WordPress
    and Tom McFarlin talk about using makepot.php but its confusing if you’re not using Linux
  • It requires using the wp-plugin as the project name which I assumed that you changed to the name of your plugin but you don’t – it has to stay wp-plugin
    so the required command is (for windows):
  • cd path\to\tools\i18n
  • php makepot.php wp-plugin path\to\plugins\your-plugin-name
  • However I got the following error when running it from windows
  • 'msguniq' is not recognized as an internal or external command
  • This appears to be because msguniq is a linux command
  • Actually this had created the your-plugin-name.pot file in the plugin directory but I just didn t realise because of the error
  • If you do want to use makepot.php use grapper’s Github i18n repo which includes all the correct WordPress files rather than the official WordPress subversion directories.

POEdit revisited

Hidden at the end of the WordPress localization document is the excellent ‘Blank WordPress POT’.

That can be put in the plugin’s languages directory and has instructions for creating the PO files from it:

The pot file include in this folder is ready to use.

  1. Double click on it and open it with poedit
  2. In poedit goto File → New Catalog from POT file…
  3. Select and Open the pot file from the languages folder
  4. Enter your name, email address, your language and country (i.e. french fr_FR, german de_DE) to the setting form
  5. Click the update button in the main poedit ui.
  6. Save the file :
  7. For a plugin like filename-xx_XX.po with xx_XX for your language and country.
  8. For a theme xx_XX.po
  9. That’s it, go to your WordPress blog and see your translation in action. N’joy your blogging!!!

This actually worked first time that I tried it – i.e. it pulled in all the translated strings.

First off you can then save the file as a my-plugin-name.pot file in the languages directory. Then you can add in your translations and save it with the locale xx_XX.po file ending and that should generate the .mo file that you need too.

Plugins

Edit: The simplest route was via the Codestyling Localization plugin.

But that is no longer available through the WordPress plugins directly – possibly because it isn’t working or from a security issue. It is still available via the developer’s own site though

Instead you can use Loco Translate which appears to be excellent – but I haven’t tried it.

(These are old instructions for Codestyling Localization) Once it is installed:

  1. Click ‘Add New Language’
  2. Select your locale and it generates an empty .po file
  3. Click ‘Rescan’ to populate the .po file
  4. Click ‘Edit’ and ‘generate mo file’ to get the .mo file out

Dealing with plugin updates

None of this solves the problem that you will lose your translation files once when the plugin is updated.

Copy your .po files into the wp-content/languages/[plugin-name] directory – which might or might not work. If yes, great, if not raise a support query (be nice and give details) with the plugin developer.

This directory is update safe basically because of the translations are loaded with the following priority:

  1. wp-content/languages/[plugin-name] (never changed by updates)
  2. wp-content/languages/plugins/ (changed with updates)
  3. wp-content/plugins/[plugin-name]/languages (changed with updates)

If developers follow this Geert DeDeckere’s excellent guide on loading WordPress language files the right way then there shouldn’t be a problem with using the wp-content/languages directory.

You can also read WooCommerce’s documentation on Making your Localization upgrade safe which recommends either Loco or using /wp-content/languages/woocommerce.

I found these two Support questions useful for learning about handling upgrades: