Page 1 of 1

Vim LÖVEr + gnu preprocessor + make

Posted: Sun Dec 08, 2013 12:06 pm
by gim
I thought I'll share my love related environment, maybe someone else will find it useful.
This will be rather long, so take your popcorn and let's start the ride...

Preprocessor
What I was missing most, was the ability to create different versions of application (game).
Sure you can just put some if statements, but a) I don't want them in 'release code' b) even if they are false, I actually don't want those if statements executing (especially inside some tight loop).

So I thought about using some kind of preprocessor. Imagine you can write following code:

Code: Select all

#ifdef DEBUG
	math.randomseed(123)
#else
	math.randomseed( tonumber(tostring(os.time()):reverse():sub(1,6)) )  -- from http://lua-users.org/wiki/MathLibraryTutorial
#endif
There are some simple preprocessors written in lua: Even SimpleLuaPreprocessor would be fine for my needs, but I thought It'll be much easier to incorporate something I'm familiar with.
So here comes in GNU C preprocessor. In quite short time I've written following Makefile:

Code: Select all

LUAHS= $(wildcard engine/*.luah *.luah)
LUAS = $(LUAHS:.luah=.lua)
#LOVE = \projects\love-0.8.0-win-x64\love.exe
LOVE = \projects\love-luajit\love.exe
RM = rm
DEFINES = -DxMAP_33 -DMAP_FIXUP_DEBUG

all: clean

clean: run
	$(RM) $(LUAS)

run: preprocess
	$(LOVE) .

preprocess: $(LUAS)

%.lua: %.luah
	$(CC) $(DEFINES) $(CFLAGS) -E -traditional -P -x c $< -o $@
So inside dir I have mixture of *.lua and *.luah files. When I run make it converts all the *.luah-s to *lua-s than it runs LOVE, and after love terminates it removes 'generated' *.lua-s (leaving non-generated ones untouched).

Vim
This worked nicely, but as stated in subject, I'm a VIM user, and with stuff above syntax highlighting wasn't working as expected. So I've modified my lua.vim file to handle that. you'll find it in attachment. (In my case it resides inside c:\users\gim\vimfiles\syntax\)

Besides handling #ifdef blocks it also adds highlighting for some love modules and functions and also adds folding, more on that later.
Image

As I've mentioned, small change in lua.vim also adds folding, this is fragment of my vimrc file:

Code: Select all

au BufRead,BufNewFile *.lua            set foldmethod=syntax relativenumber
au BufRead,BufNewFile *.luah           set foldmethod=syntax relativenumber

map <f7> :make<cr>
cope 5
This does two things a) turns on syntax-based folding for *.lua(h) files and b) maps f7 to make, so I can run LOVE using make from within VIM :)
This is how file actually looks right after loading with folding enabled:
Image

errors (overkill?)
This all was working quite fine, but the problem I had is that whenever exception happened vim was pointing me at wrong locations
(to *.lua file instead of *.luah and numbers were all wrong - cause after preprocessing, line numer inside *.luah != line number in *.lua).

So I've did few things to fix this. First I've changed the way files are generated, and now from single *.luah I'm generating two files: *.lua and *.lua_x
*.lua_x is 'full' cpp output along with line informations (-P flag dropped), those informations are stripped with sed and output placed in *.lua, so corresponding line
from Makefile now looks like this:

Code: Select all

%.lua: %.luah
	$(CC) $(DEFINES) $(CFLAGS) -E -traditional -x c $< -o $@_x
	sed "s/^#.*//" $@_x > $@
Now Vim docs suggest creating filter for make (it receives make output so there is also love stacktrace there :)).
So I've written small script in python, that does few things:
  1. In the input, it looks for beginning of stack trace (naively with: if line.startswith('Error'))
  2. It check if file exist, if not it assumes this file was produced from *.luah file, in such case:
    • It opens *_x (extended) file, and goes through it, checking the cpp # directives, as they contain ORIGINAL line numbers
  3. Additionally it precedes every line with "Error" (will be handy in next step)

Code: Select all

#!/usr/bin/env python
import sys,re,os,os.path

gccNum=re.compile(r'# (\d+)')
def properNumber(fName, lineNo):
	no = 0
	virt = 0
	for l in open(fName+'_x', 'r'):
		no += 1
		virt += 1
		if no == lineNo:
			break
		m = gccNum.match(l)
		if m:
			virt = int(m.group(1)) -1
	return virt

catMode=False
errorLine=re.compile(r'\s([^[:]+?):(\d+):(.*)')
for line in sys.stdin:
	if line.startswith('Error: '):
		catMode=True
		line=line[6:]
	if catMode:
		m = errorLine.search(line)
		if m and m.group(1).endswith('.lua'):
			prefix='Error: '
			if os.path.exists(m.group(1)):
				print prefix+line,
			else:
				lineNo = properNumber(m.group(1), int(m.group(2)))
				print prefix+m.group(1)+'h:'+str(lineNo)+':'+m.group(3)
		# if you want to drop 'non-file' lines, drop this else block
		else:
			print line.strip()
Now there's only one thing to do, tell vim to use preprocessor, and inform it how errorline looks like, _vimrc:

Code: Select all

au BufRead,BufNewFile *.lua            set foldmethod=syntax relativenumber mp=make\\\|python\ $HOME/vimfiles/makelove.py errorformat=Error:\ %f:%l:\ %m
au BufRead,BufNewFile *.luah           set foldmethod=syntax relativenumber mp=make\\\|python\ $HOME/vimfiles/makelove.py errorformat=Error:\ %f:%l:\ %m
And that's how it finally looks:
Image

now I can Enter or double click inside cope window :)

edit: forgot to attach lua.vim file

Re: Vim LÖVEr + gnu preprocessor + make

Posted: Sun Dec 08, 2013 7:03 pm
by Inny
As a linuxy guy, this is very neat that you worked out how to do it. I would never use it though. The Make files, yeah I do that, but just for bundling. A lot of the stuff that I consider "debug code" I actually do want to be able to turn it on and off and know that the "production" behavior is what I expected. It's something I learned from my C++ days that debug code is really stuff you want to be able to trigger on and off with a command line argument, not a compiler directive.

The custom vim syntax file though, that looks like I might make use of it. :P

Re: Vim LÖVEr + gnu preprocessor + make

Posted: Sun Dec 08, 2013 7:52 pm
by Nsmurf
Inny wrote:It's something I learned from my C++ days that debug code is really stuff you want to be able to trigger on and off with a command line argument, not a compiler directive.
I'd go further, and make a keycombo like Ctrl + F1 toggle debug mode while it's running.
gim wrote:--Snip--
All very cool, but I'll stick with my :!love .
Also, it strikes me as strange to use windows 8 and vim. :P
Anyways, the preprocessors look cool, but I don't see a situation where I would need them.

Re: Vim LÖVEr + gnu preprocessor + make

Posted: Sun Dec 08, 2013 9:39 pm
by gim
Nsmurf wrote: Also, it strikes me as strange to use windows 8 and vim. :P
eagle eye ;) what can I say, accidents happen.

Re: Vim LÖVEr + gnu preprocessor + make

Posted: Mon Dec 09, 2013 4:03 am
by Nsmurf
gim wrote:
Nsmurf wrote: Also, it strikes me as strange to use windows 8 and vim. :P
eagle eye ;) what can I say, accidents happen.
Haha, The awesomeness of vim makes up for the lameness of win8. Also is your avatar a picture of rms, and yet you use vim? ^^
Don't worry about what OS you use here though, most likely, nobody cares.

Re: Vim LÖVEr + gnu preprocessor + make

Posted: Mon Dec 09, 2013 9:46 am
by gim
Nsmurf wrote: Haha, The awesomeness of vim makes up for the lameness of win8. Also is your avatar a picture of rms, and yet you use vim? ^^
I thought RMS + obey will nicely fit together :>
Nsmurf wrote: Don't worry about what OS you use here though, most likely, nobody cares.
Actually I was mainly linux user for quite some time (7yrs? and many weird window managers: fluxbox, blackbox, e17, last one was my favourite) but recently (well 4yrs I guess) I'm mostly using windows.

I must admit I like linux more, but I wouldn't say one OS is better than the other. They are just different that's all.

Vim probably has steep learning curve (especially if one is accustomed to clicking, instead of writing), but it definitely pays off.
I have to say, it makes me smile, when I see friends at work (Windows only), struggling to do some simple things in notepad++ when in vim it's a breeze. (The same goes for the command line, and mostly, that's because they don't know basic gnu commandline toolchain: sed, awk, tr, cut, but at least some of them know grep ;))