Learn Lua Programming Language
Learn lua for config neovim editor 😜
What is Lua?
Lua is a procedural programming language used to develop software, work with machine learning and create all sorts of games, from a basic text game all the way to VR games.
Lua projects
- Adobe Photoshop Lightroom
- Apache HTTP server
- Awesome WM
- Roblox
- Angry Birds
- ...
Install lua
: brew install lua
Test lua
installation: lua -v
Basics
Print text to screen
print("Hello World")
To run script: lua main.lua
For writing comments
-- single line comment
print("Hello World")
--[[
this is multiline comment
]]
To concatenate some strings, use ..
operator
print('Hello' .. ' ' .. 'World' .. '!')
Data types and variables
Some types
nil
: nothingnumber
: 1, 1.24, 0.1, 44,..string
: 'hello', "hello"boolean
: true - falsetable
: array - dictionary
To define new variable, use local
keyword
local my_name = 'Hieu Nguyen Trong'
print(my_name)
local a
print(a) -- zero value: nil
a = 2
local b = 3
print(a + b)
a = 'hieu'
a = true
local
will create a variable in local scope.
local name = 'hieu'
local surname = 'trong'
local fullname = surname .. ' ' .. name
local = description = [[
Multiline string
]]
You can also think of a box as a file
, if you use multiple
lua
files in your program, then local
variables can only
be accessed in their respective files, but global
scope
variables can be accessed from outside the file, meaning your
variable names
may overwrite the variable name
inside another file.
-- global scope variable
Name = 'Hieu Nguyen Trong'
_G.Name = 'Hieu Nguyen Trong'
-- local scope variable
local name = 'Hieu Nguyen Trong'
Get type of variables
str = 'hieu'
print(type(str))
Math in Lua
Converting a string to number
local str = '1'
print(type(str)) -- string
local n = tonumber(str)
print(type(n)) -- number
Operators
+
-
*
/
%
: modulus^
: power
Get PI
math.pi
: get PI
Get random number
math.randomseed(os.time())
math.random() -- random value between 0 and 1
math.random(1, 100) -- random value between 0 and 1
Get min values
print(max.min(10, 1, 2, 3, 4))
print(max.max(10, 1, 2, 3, 4))
Strings in Lua
local str = 'Hello World!'
print(str)
print(type(str)) -- string
local multi = [[
multiline
string
]]
print(multi)
Get length of the string (number of bytes)
local str = "Hello World"
print(#str)
Convert number to string
local x = 22
local str = tostring(x)
print(str)
Newline character
print('Hello\nWorld')
Some string functions
local str = "Hello World"
print(string.lower(str))
print(string.upper(str))
print(string.len(str))
Substring
local str = "Hello World"
print(string.sub(str, 1, 5))
Get ASCII character
print(string.char(97))
print(string.byte("a"))
Variable pattern
local str = 'Hello World'
local begin, ending = string.find(str, 'orl')
print('Begin: '..begin.."\nEnd: "..ending)
If
statements
if true then
print('True')
elseif true then
print('True')
else
print('False')
end
Comparison operator
>
<
>=
<=
==
~=
Logical operators
and
or
not
Loops
Loop from 1
to 10
, each time plus i
to 1
for i = 1, 10, 1 do
print(i)
end
Loop backward
local start_val, end_val, step_val = 1, 10, 1
for i = start_val, end_val, step_val do
print(i)
end
Loop over array
local arr = {1,2,3,4,5}
for i = 1, #arr do
print(arr[i])
end
While loop
local peeps = 10
while peeps > 0 do
print('People left at party: ' .. peeps)
peeps = peeps - 1
end
Infinite loop
while True do
print('Inifinite loop')
end
Repeat .. Until
local x = 1
repeat
print('hello')
x = x + 1
until x > 10
Get user input
print("What's your name? ")
local input = io.read()
print("Hello " .. input)
io.write('Print one the same line: ')
io.write('Hello')
Tables
Tables represent things like
- array
- record
- set
- list
A table is almost like a container for multiple variables.
Create a table with {}
-- table or array (for convinient)
local arr = {1,2,3,4,5}
print(arr)
-- index from 1
print(arr[1])
print(arr[2])
print(arr[3])
print(arr[4]) -- nil
Sort values
local arr = {1,2,3}
table.sort(arr)
for i = 1, #arr do
print(arr[i])
end
Add new item into an array
local arr = {1,2,3}
table.insert(arr, 4)
table.remove(arr, 1)
print(arr)
Joining table to a string
local arr = {'hello', 'world'}
print(table.concat(arr, ' ')) -- hello world
2D array
local matrix = {
{1,2,3},
{4,5,6},
{7,8,9}
}
print(matrix[1][1])
Functions
Local functions
local function greet()
print('Hello World')
end
greet()
Global functions
_G.function Greet()
print('Hello World')
end
Function params
local function greet(name)
print('Hello ' .. name)
end
greet('Hieu')
Set default value
local function greet(name)
name = name or 'Stranger'
print('Hello ' .. name)
end
greet()
greet('Hieu')
Return value from functions
local function sum(n1, n2)
local y = n1 + n2
return y
end
sum(1,2)
-- y is local scope, cannot be accessed here
print(y)
Assign function
local fn = function ()
print('Hello World')
end
fn()
Return multiple value
local fn = function ()
return 1, 2
end
local n1, n2 = fn()
print(n1, n2)
local _, n3 = fn()
print(n3)
Function return function
local function counter()
local count = 0
return function()
count = count + 1
return count
end
end
local fn = counter()
print(fn())
Pass multiple params
local function sum(...)
local sum = 0
for _, value in pairs({...}) do
sum += value
end
return sum
end
Co-Routines
local routine_1 = coroutine.create(
function ()
for i=1, 10, 1 do
print('Routine 1')
if i == 5 then
coroutine.yield()
end
end
end
)
local routine_func = function ()
for i = 11, 20 do
print('Routine2')
end
end
local routine_2 = coroutine.create(routine_func())
coroutine.resume(routine_1)
print(coroutine.status(routine_1))
coroutine.resume(routine_1)
print(coroutine.status(routine_1))
Working with files
Write to file
io.output('myfile.txt')
io.write('Hello World')
io.close()
Read file
io.input('myfile.txt')
local file = io.read("*all")
-- local file = io.read("*line")
io.close()
print(file)
os
module
The print(os.time())
print(os.time({
year = 2000,
month = 10,
day = 1,
hour = 13,
min = 20,
sec = 10
}))
print(os.date())
print(os.getenv('PATH'))
print(os.rename('myfile.txt', 'rename.txt'))
print(os.remove('rename.txt'))
print(os.execute('ls'))
Custom modules
A module is basically a lua file that returns a single table when called.
A package is a collection of modules.
Create new file mymath.lua
. Now we have 2 files
main.lua
mymath.lua
-- mymath.lua
mmath = {}
-- global function
function mmath.add(x, y)
return x + y
end
return mmath
-- main.lua
local mod = require('mymath')
print(mod.add(1,2))
OOP
local function Pet(name)
name = name or 'Luis'
return {
name = name,
status = 'hungry'
feed = function(self)
self.status = 'full'
end
}
end
local cat = Pet('Kitty')
print(cat.name)
print(cat.status)
cat.feed()
print(cat.status)
Inheritance
local function Dog(name, breed)
local dog = Pet(name)
dog.breed = brred
dog.loyalty = 0
dog.isLoyal = function(self)
return self.loyalty >= 10
end
dog.bark = function(self)
print('Woof')
end
return dog
end
local dog = Dog('Doggy', 'Poodle')
if dog:isLoyal() then
print('Loyal')
end
Meta methods
local function addTableValues(x, y)
return x.num + y.num
end
local tbl1 = { num = 50 }
local tbl2 = { num = 10 }
-- overload operator
local metatable = {
__add = addTableValues
__sub = function (x, y)
return x.num - y.num
end
}
setmetatable(tbl1, metatable)
local asn = tbl1 + tbl2
print(ans)
Next?
- LuaRocks: online package repository
- Love2d: game engine
Setup Neovim with Lua
Prebuild vim
- AstroVim
- LunarVim
Required
- iTerm2
- Nerd Fonts: Meslo Nerd font
Install NeoVim v0.8: brew install neovim
Checking neovim: nvim --version
Config directory
.config/
nvim/
init.lua
lua/
[you name]/
core/
colorscheme.lua
options.lua
keymaps.lua
plugins/
lualine.lua
telescope.lua
vim-tree.lua
...
plugins-setup.lua
Basic options & settings
Import core files to init.lua
require('lua.dalatcoder.core.options')
require('lua.dalatcoder.core.keymaps')
require('lua.dalatcoder.core.colorscheme')
Add some options in lua.dalatcoder.core.options
-- opt table ref
local opt = vim.opt
-- line numbers
opt.relativenumber = true
opt.number = true
-- tabs & indentation
opt.tabstop = 2
opt.shiftwidth = 2
opt.expandtab = true
opt.autoindent = true
-- line wrapping
opt.wrap = false
-- search settings
opt.ignorecase = true
opt.smartcase = true
-- cursor line
opt.cursorline = true
-- appearance
opt.termguicolors = true
opt.background = "dark"
opt.signcolumn = "yes"
-- backspace
opt.backspace = "indent,eol,start"
-- clipboard
opt.clipboard:append("unnamedplus")
-- split windows
opt.splitright = true
opt.splitbelow = true
-- daw include -
opt.iskeyword:append("-")
Packer Plugin Manager
Require in init.lua
require('lua.dalatcoder.plugins-setup')
require('lua.dalatcoder.core.options')
require('lua.dalatcoder.core.keymaps')
require('lua.dalatcoder.core.colorscheme')
Setup packer
in lua.dalatcoder.plugins-setup
-- auto install packer if not installed
local ensure_packer = function()
local fn = vim.fn
local install_path = fn.stdpath("data") .. "/site/pack/packer/start/packer.nvim"
if fn.empty(fn.glob(install_path)) > 0 then
fn.system({ "git", "clone", "--depth", "1", "https://github.com/wbthomason/packer.nvim", install_path })
vim.cmd([[packadd packer.nvim]])
return true
end
return false
end
local packer_bootstrap = ensure_packer() -- true if packer was just installed
-- autocommand that reloads neovim and installs/updates/removes plugins
-- when file is saved
vim.cmd([[
augroup packer_user_config
autocmd!
autocmd BufWritePost plugins-setup.lua source <afile> | PackerSync
augroup end
]])
-- import packer safely
local status, packer = pcall(require, "packer")
if not status then
return
end
-- add list of plugins to install
return packer.startup(function(use)
-- packer can manage itself
use("wbthomason/packer.nvim")
use("bluz71/vim-nightfly-guicolors") -- preferred colorscheme
if packer_bootstrap then
require("packer").sync()
end
end)
Configure colorscheme in lua.dalatcoder.core.colorscheme
vim.cmd("colorscheme nightfly")
But, to be safety, we can check before active the theme
-- set colorscheme to nightfly with protected call
-- in case it isn't installed
local status, _ = pcall(vim.cmd, "colorscheme nightfly")
if not status then
print("Colorscheme not found!") -- print error if colorscheme not installed
return
end
Custom keymaps in lua.dalatcoder.core.keymaps
-- set leader key to space
vim.g.mapleader = " "
-- set key in insert mode
-- use jk to exit insert mode
keymap.set("i", "jk", "<ESC>")
-- set key in normal mode
-- clear search highlights
keymap.set("n", "<leader>nh", ":nohl<CR>")
Window related plugins:
-
vim-tmux-navigator
: usesCtr-h,j,k,l
to move between windows and tmux -
vim-maximizer
: maximize splits and restore them back to their original size
Essential plugins
vim-surround
ReplaceWithRegister
Comment.nvim
Comment plugin
- Create plugin config file at:
dalatcoder.plugins.comment.lua
-- import comment plugin safely
local setup, comment = pcall(require, "Comment")
if not setup then
return
end
-- enable comment
comment.setup()
Import config file in init.lua
-- plugin configurations
require("dalatcoder.plugins.comment")
Use cases:
- Comment current line:
gcc
- Comment 5 lines below:
gc5j
Plenary plugin includes lua functions that many plugins use
File explorer with nvim-tree
- Config plugin at
dalatcoder.plugins.nvim-tree.lua
- Import plugin config file at
init.lua
- Create keymap to open/close quickier at
dalatcoder.core.keymaps
VScode Like Icons with nvim-web-devicons
Config status line with lualine.nvim
- Config plugin at
dalatcoder.plugins.lualine.lua
- Import plugin config file at
init.lua
Config Telescope Fuzzy Finder
- Install
ripgrep
:brew install ripgrep
- Add plugin
telescope-fzf-native
- Add plugin
telescope.nvim
- Config plugin at
dalatcoder.plugins.telescope.lua
- Import plugin config file at
init.lua
- Create keymap to active telescope at
dalatcoder.core.keymaps
Setup basic autocompletion
- Add plugin
nvim-cmp
: autocompletion - Add plugin
cmp-buffer
: recommend text from current buffer - Add plugin
cmp-path
: recommend file path - Add plugin
LuaSnip
: snippet engine - Add plugin
cmp_luasnip
: recommend snippets - Add plugin
friendly-snippets
: collections of useful snippets - Config plugin at
dalatcoder.plugins.nvim-cmp.lua
- Import plugin config file at
init.lua
Configuring LSP - Language Server Protocol, it'll give us the ability to have really smart auto code completion and also the ability to perform code actions to fix problems in our code.
Add plugins for managing and installing LSP servers
- Add
mason.nvim
plugin, use this plugin as the source of truth to manage LSP servers - LSP is built into neovim but the LSP servers themselves need to be installed
- Add
nvim-lspconfig
for configuring LSP servers - Add
mason-lspconfig
as an adapter betweenmason
andlspconfig
plugins - Add
cmp-nvim-lsp
config LSP servers so that they appear in Auto Completion lspsaga.nvim
will add enhanced UI to our LSP experiencetypescript.nvim
to add more functionality to the TS serverlspkind.nvim
add vscode like icons to our Auto Completion- Create all related config files at
dalatcoder.plugins.lsp
lsp.mason.lua
lspconfig.lua
for configuring all LSP serverslspsaga.lua
for configuring LSP Saga
- Import plugin config file at
init.lua
Open neovim, press command :Mason
to install LSP
servers
Formating and Linting
- Add
null-ls.nvim
: used to config formatter and linter - Add
mason-null-ls.nvim
: adapter - Config plugin at
dalatcoder.plugins.lsp.null-ls
Highlighting with TreeSitter nvim-treesitter
Auto closing with nvim-autopairs
and nvim-ts-autotag
Setup LSP for Python:
- Install
PyLSP
- Install dependencies:
:PylspInstall pyls-flake8 pylsp-mypy pyls-isort
Setup Tmux
Tmux is what is known as terminal multiplexer which gives us the ability to manage sessions, windows and panes inside the terminal
- Install tmux with:
brew install tmux
- Check installation with:
tmux -V
- Create config file at:
~/.tmux.conf
Working with sessions
- Create new session:
tmux new -s Session
- Exit session:
tmux detach
- Get session list:
tmux ls
- Open existing session:
tmux attach -t Session
- Kill existing session:
tmux kill-session -t Session
Inside a tmux session, we can use C-a s
to list session and navigate between sessions with j
and k
In each session, you will have
window
pane
A window is basically a collection of split panes.
Create new split panes
- Vertical:
C-a %
, remap toC-a |
- Horizontal:
C-a '
, remap toC-a -
Resize panes
j
k
l
h
Using m
key to maximize a tmux pane
Config plugin to navigate between tmux pane
- Install
TPM
- Tmux Plugin Manager git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm
- Using plugin
vim-tmux-navigator
- To install plugins, press
C-a I
We can use this plugin to navigate between tmux panes and neovim
Working with Windows in Tmux
C-a c
- Navigate between window
C-a [number]
- Rename window with
C-a ,
- Also navigate with
C-a n
orC-a p
- List all windows with
C-a w
Use cases
- Backend project on a single window
- Front project on a seperated window
- Several panes in each window for writing codes and running things
- Maximize code pane with
C-a m
Configuring Vim Movements within tmux
- Enable copy/vi mode
C-a [
- Use
h
,j
,k
,l
to move orJ
,K
- Use
C-D
,C-U
- Copy with
v
andy
or using mouse - To exit copy/vi mode
C-c
Adding theme
Add some more plugins to save tmux session