-
-
Notifications
You must be signed in to change notification settings - Fork 356
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit d8c4bfa
Showing
486 changed files
with
146,040 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
|
Oops, something went wrong.