tech

[English] [Japanese]

A.Let's have more fun in a modern development environment

What editor do you use for Lua development?

A modern feature-packed environment like Lua Development Tools, Atom, VSCode? Or is it a classic environment like emacs or vim?

In either environment, are you unsatisfied with the completion function while coding Lua?

Lua's completion function is pretty smart in many cases, but there are quite a few cases where completion doesn't work, right?

Even just checking a little, it seems that completion does not work in the following situations.

  • Completion of the field of the method that the object passed as the argument of the function has
  • Complementing object-oriented programming with metatables

In light processing, the above problem may not bother you so much, but when you write processing of a certain scale, it does bother you.

Lua's transcompiler LuneScript provides a completion function at the compiler level so that completion works in any situation.

Here, I will introduce modern development support that can be used when coding LuneScript.

Specifically:

  • auto indent
  • Code completion feature
  • Check type information at cursor position
  • Syntax error checking function
  • subfile-aware search

auto indent

Auto-indent is the most basic support feature when coding.

LuneScript provides a formatter that does auto-indentation.

In the emacs environment, auto-indent can be used simply by setting the lns-mode shown below.

Environments other than emacs are currently not supported. However, the main functionality of auto-indent is handled by an external tool formatter written in LuneScript. emacs just uses the amount of indentation it gets with that formatter. Therefore, you can use the auto indent function even in other environments by creating a linkage part with formatter.

Code completion feature

LuneScript provides completion for class fields.

For example, in code like

// @lnsFront: ok
class Super {
   pub let val:int;
   pri let val2:int { pub };
   pub fn funcsuper():int! {
      return 0;
   }
}
class Test extend Super {
   pub fn __init( val: int ) {
      super( val, val + 1 );
   }
   pub fn func( val: int ):int {
      return 1;
   }
}
let test = new Test( 1 );

You can do completion for the fields of test like this:

https://ifritjp.github.io/doc/LuneScript/comp1.gif

Here's what I want you to notice:

  • Super and Test fields are listed as candidates, recognizing the inheritance relationship
  • Private val2 members of Super are delisted in recognition of access control
  • A constructor (__init) that cannot be accessed from the instance is excluded from the list
  • It lists get_val2() that you don't define

It's a natural function, but it's surprisingly rare that the compiler itself provides this natural function.

Check type information at cursor position

LuneScript supports type inference.

This allows you to proceed with coding without having to expose type information.

For example, the following code does not have any explicit type.

// @lnsFront: ok
foreach val, key in { "abc": 1, "xyz": 10 } {
  print( key, val );
}

This is convenient, but the drawback is that you can't check the type.

Therefore, we provide a function that allows you to check the type of the symbol at the cursor position.

You can see the type information for a symbol by moving the cursor to the symbol you want to see and executing C-c I .

Syntax error checking function

Since LuneScript is a compiler, it naturally has a Syntax error checking function.

Based on this error check information, error locations can be displayed on the editor.

For example, with a source like

// @lnsFront: ok
fn func( val: int ) {
   print( val );
}
let map = { "a": 1, "b":2 };

Adding the following process will result in an error.

https://ifritjp.github.io/doc/LuneScript/error.gif

https://ifritjp.github.io/doc/LuneScript/error2.PNG

This means that the result of accessing map type item will be nilable type, and if it is given to func(), a type mismatch error between int! and int will occur.

Errors such as these that are often overlooked can be easily checked in the editor.

subfile-aware search

LuneScript has the function subfile to divide a file that defines a large module into multiple files and define it.

By using this function, you will be released from the stress of having a large file and a heavy editor.

However, since the file is divided, there is a drawback that the searchability in the module worsens.

For example, if a module consists of owner.lns, sub1.lns, sub2.lns, sub3.lns, to find where data in a module is accessed, use owner.lns, sub1.lns , sub2.lns, and sub3.lns.

This is a cumbersome operation.

This troublesome operation is automatically performed at the time of searching.

Specifically, if you cannot find it by searching with owner.lns, then switch to sub1.lns and search. If not found in sub1.lns, then switch to sub2.lns and search. … to do this automatically.

setting

This is the lns-mode setting for emacs.

(require 'lns-conf)
;;(require 'lns-flymake)
(require 'lns-flycheck)
(require 'lns-company-mode)
;;(require 'lns-auto-complete)
(require 'lns-helm)

Select either code completion or syntax check according to your environment.

  • code completion

    • flycheck
    • flymake
  • Syntax check

    • company-mode
    • auto-complete

LuneScript's flymake and auto-complete support is not maintained. We recommend using flycheck, company-mode.

Faster auto-indent

If you just get it from github, the auto-indenting process will work with the script version of the formatter. The scripted version of the formatter is slow and can take a long time to process large source files.

To speed this up, build a Go version of the formatter.

To build the Go version, run the following against the project you got from github.

$ cd tools/formatter
$ make build-go

customization

You can change the auto indent settings with the following setting items.

  • lns-get-formatter-path

    • Register a function that returns the path of the formatter.
  • lns-proj-info-check-useing-indent-command

    • Register a function that returns whether to use the formatter.

project

LuneScript manages the module path as a relative path from the project. Therefore, emacs needs to know the root directory of the project.

To make emacs aware of your project's root directory, create the following lune.js file in your project's root directory.

lune.js

In this lune.js file, write:

{}

module path

If you create lune.js in the following location, the module path for proj/foo/bar/module1.lsn will be foo.bar.module1 .

proj/lune.js
proj/foo/bar/module1.lsn

lastly

This function has been confirmed to work on emacs. By the way, code completion corresponds to company-mode, auto-complete, syntax error check corresponds to flymake, flycheck.

By default, LuneScript provides settings for emacs, but emacs does only frontend control, and LuneScript does all the backend.

In other words, porting to environments other than emacs is quite possible. However, since I myself am an emacs user, I develop emacs with the highest priority.

If you are interested in LuneScript, I would appreciate it if you could support environments other than emacs.