Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
rxi committed Dec 28, 2019
0 parents commit d8c4bfa
Show file tree
Hide file tree
Showing 486 changed files with 146,040 additions and 0 deletions.
19 changes: 19 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Copyright (c) 2019 rxi

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# lite
![screenshot](https://user-images.githubusercontent.com/3920290/71542771-52265880-2962-11ea-8382-c92f8e10b734.png)

A lightweight text editor written in Lua

## Overview
lite is a lightweight text editor written mostly in Lua — it aims to provide
something practical, pretty, *small* and responsive, implemented as simply as
possible; easy to modify and extend, or to use without doing either.

## Get
Go to the [Releases](#TODO) page to download precompiled binaries for Windows or
Linux. Additional functionality can be added through plugins which are available
from the [plugins repository](#TODO).

## Building
You can build the project yourself on Linux using the provided `build.py`
script. Note that the project does not need to be rebuilt if you are only making
changes to the Lua portion of the code.

## Contributing
Any additional functionality that can be added through a plugin should be done
so as a plugin, after which a pull request to the [plugins repository](#TODO)
can be made. In hopes of remaining lightweight, pull requests adding additional
functionality to the core will likely not be merged. Bug reports and bug fixes
are welcome.

## License
This project is free software; you can redistribute it and/or modify it under
the terms of the MIT license. See [LICENSE](LICENSE) for details.
29 changes: 29 additions & 0 deletions build.config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import os

cflags = [ "-Wall", "-O3", "-g", "-DLUA_USE_POPEN" ]
lflags = [ "-lSDL2", "-lm" ]
include = [ "src" ]
output = "lite"


if "sanitize" in opt:
log("address sanitizer enabled")
cflags += [ "-fsanitize=address" ]
lflags += [ "-fsanitize=address" ]


if "windows" in opt:
compiler = "x86_64-w64-mingw32-gcc"
output += ".exe"
cflags += [ "-Iwinlib/SDL2-2.0.10/x86_64-w64-mingw32/include" ]
lflags += [ "-Lwinlib/SDL2-2.0.10/x86_64-w64-mingw32/lib" ]
lflags = [ "-lmingw32", "-lSDL2main" ] + lflags
lflags += [ "-lwinmm" ]
lflags += [ "-mwindows" ]
lflags += [ "res.res" ]

def pre():
os.system("x86_64-w64-mingw32-windres res.rc -O coff -o res.res")

def post():
os.remove("res.res")
306 changes: 306 additions & 0 deletions build.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,306 @@
#!/usr/bin/python2.7
import os, sys, platform, shutil
import re, threading, time, json
from os import path
from hashlib import sha1
from multiprocessing import cpu_count


config_file = "build.config.py"
cache_dir = ".buildcache"
object_dir = path.join(cache_dir, "obj")
cache_file = path.join(cache_dir, "cache.json")
max_workers = cpu_count()


config = {
"compiler" : "gcc",
"output" : "a.out",
"source" : [ "src" ],
"include" : [],
"cflags" : [],
"lflags" : [],
"run" : "./{output}"
}


Hint, Warn, Error = range(3)
log_prefix = {
Hint: "\x1b[32mHint:\x1b[0m",
Warn: "\x1b[33mWarn:\x1b[0m",
Error: "\x1b[31;1mError:\x1b[0m"
}


log_lock = threading.Lock()

def log(msg, mode=Hint):
log_lock.acquire()
print log_prefix[mode], msg
log_lock.release()


def error(msg):
log(msg, mode=Error)
os._exit(1)


def load_config(filename):
""" loads the given config file into the `config` global dict """
if not path.exists(filename):
error("config file does not exist: '%s'" % filename)

d = {
"opt": sys.argv,
"platform": platform.system(),
"error": error,
"log": log,
"Hint": Hint,
"Warn": Warn,
"Error": Error
}
execfile(filename, d)
config.update(d)

if len(config["source"]) == 0:
error("no source directories specified in config")


def load_cache(cache_file):
if not path.exists(cache_file):
return { "hashes": [], "cmd": "" }
with open(cache_file) as fp:
log("loaded cache")
return json.load(fp)


def update_cache(cache_file, obj):
with open(cache_file, "wb") as fp:
json.dump(obj, fp, indent=2)
log("updated cache")


def resolve_file(filename, dir):
""" finds the actual location of an included file """
f = path.join(dir, filename)
if path.exists(f):
return short_name(f)

for dir in config["include"]:
f = path.join(dir, filename)
if path.exists(f):
return short_name(f)


file_info_cache = {}

def get_file_info(filename):
""" returns a dict of file info for the given file """
if filename in file_info_cache:
return file_info_cache[filename]

hash = sha1()
includes = []

with open(filename) as fp:
for line in fp.readlines():
# get includes
if "#include" in line:
match = re.match('^\s*#include\s+"(.*?)"', line)
if match:
includes.append( match.group(1) )
# update hash
hash.update(line)
hash.update("\n")

res = { "hash": hash.hexdigest(), "includes": includes }
file_info_cache[filename] = res
return res


def short_name(filename):
""" returns the filename relative to the current path """
n = len(path.abspath("."))
return path.abspath(filename)[n+1:]


def get_deep_hash(filename):
""" creates a hash from the file and all its includes """
h = sha1()
processed = set()
files = [ resolve_file(filename, ".") ]

while len(files) > 0:
f = files.pop()
info = get_file_info(f)
processed.add(f)

# update hash
h.update(info["hash"])

# add includes
for x in info["includes"]:
resolved = resolve_file(x, path.dirname(f))
if resolved:
if resolved not in processed:
files.append(resolved)
else:
log("could not resolve file '%s'" % x, mode=Warn)

return h.hexdigest()


def build_deep_hash_dict(cfiles):
""" returns a dict mapping each cfile to its hash """
res = {}
for f in cfiles:
res[f] = get_deep_hash(f)
return res


def get_cfiles():
""" returns all .h and .c files in source directories """
res = []
for dir in config["source"]:
for root, dirs, files in os.walk(dir):
for file in files:
if file.endswith((".c", ".h")):
f = path.join(root, file)
res.append( short_name(f) )
return res


def build_compile_cmd():
""" creates the command used to compile files """
lst = [
config["compiler"],
" ".join(map(lambda x: "-I" + x, config["include"])),
" ".join(config["cflags"]),
"-c", "{infile}", "-o", "{outfile}"
]
return " ".join(lst)


def obj_name(filename):
""" creates the object file name for a given filename """
filename = re.sub("[^\w]+", "_", filename)
return filename[:-2] + "_" + sha1(filename).hexdigest()[:8] + ".o"


def compile(cmd, filename):
""" compiles the given file into an object file using the cmd """
log("compiling '%s'" % filename)

outfile = path.join(object_dir, obj_name(filename))

res = os.system(cmd.format(infile=filename, outfile=outfile))
if res != 0:
error("failed to compile '%s'" % filename)


def link():
""" links objects and outputs the final binary """
log("linking")
lst = [
config["compiler"],
"-o", config["output"],
path.join(object_dir, "*"),
" ".join(config["lflags"])
]
cmd = " ".join(lst)
res = os.system(cmd)
if res != 0:
error("failed to link")


def parallel(func, workers=4):
""" runs func on multiple threads and waits for them all to finish """
threads = []
for i in range(workers):
t = threading.Thread(target=func)
threads.append(t)
t.start()
for t in threads:
t.join()



if __name__ == "__main__":

start_time = time.time()

load_config(config_file)
run_at_exit = False
output_dir = path.join(".", path.dirname(config["output"]))
cache = load_cache(cache_file)
cmd = build_compile_cmd()

if "run" in sys.argv:
run_at_exit = True

if cache["cmd"] != cmd:
sys.argv.append("clean")

if "clean" in sys.argv:
log("performing clean build")
shutil.rmtree(cache_dir, ignore_errors=True)
cache = load_cache(cache_file)


if not path.exists(object_dir):
os.makedirs(object_dir)

if not path.exists(output_dir):
os.makedirs(output_dir)


if "pre" in config:
config["pre"]()


cfiles = get_cfiles()
hashes = build_deep_hash_dict(cfiles)


# delete object files for cfiles that no longer exist
obj_files = set(map(obj_name, cfiles))
for f in os.listdir(object_dir):
if f not in obj_files:
os.remove(path.join(object_dir, f))


# build list of all .c files that need compiling
pending = []
for f in cfiles:
if f.endswith(".c"):
if f not in cache["hashes"] or cache["hashes"][f] != hashes[f]:
pending.append(f)


# compile files until there are none left
def worker():
while True:
try:
f = pending.pop()
except:
break
compile(cmd, f)


parallel(worker, workers=max_workers)


link()
update_cache(cache_file, { "hashes": hashes, "cmd": cmd })

if "post" in config:
config["post"]()


log("done [%.2fs]" % (time.time() - start_time))


if run_at_exit:
log("running")
cmd = config["run"].format(output=config["output"])
os.system(cmd)
10 changes: 10 additions & 0 deletions build_release.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash
./build.py release windows
./build.py release
rm lite.zip 2>/dev/null
cp winlib/SDL2-2.0.10/x86_64-w64-mingw32/bin/SDL2.dll SDL2.dll
strip lite
strip lite.exe
strip SDL2.dll
zip lite.zip lite lite.exe SDL2.dll data -r

Loading

0 comments on commit d8c4bfa

Please sign in to comment.