all: require calling `optfn() ?` / `optfn() or {...}` for `fn optfn() ? {}`

pull/8357/head
Delyan Angelov 2021-01-26 16:43:10 +02:00
parent 97103f680a
commit e5a84719ca
No known key found for this signature in database
GPG Key ID: 66886C0F12D595ED
90 changed files with 1994 additions and 1832 deletions

View File

@ -70,7 +70,8 @@ fn main() {
date := time.unix(commit_date.int()) date := time.unix(commit_date.int())
mut out := os.create('table.html') ? mut out := os.create('table.html') ?
// Place the new row on top // Place the new row on top
table = '<tr> table =
'<tr>
<td>$date.format()</td> <td>$date.format()</td>
<td><a target=_blank href="https://github.com/vlang/v/commit/$commit">$commit</a></td> <td><a target=_blank href="https://github.com/vlang/v/commit/$commit">$commit</a></td>
<td>$message</td> <td>$message</td>
@ -80,15 +81,15 @@ fn main() {
<td>${diff4}ms</td> <td>${diff4}ms</td>
</tr>\n' + </tr>\n' +
table.trim_space() table.trim_space()
out.writeln(table) out.writeln(table) ?
out.close() out.close()
// Regenerate index.html // Regenerate index.html
header := os.read_file('header.html') ? header := os.read_file('header.html') ?
footer := os.read_file('footer.html') ? footer := os.read_file('footer.html') ?
mut res := os.create('index.html') ? mut res := os.create('index.html') ?
res.writeln(header) res.writeln(header) ?
res.writeln(table) res.writeln(table) ?
res.writeln(footer) res.writeln(footer) ?
res.close() res.close()
} }
exec('git checkout master') exec('git checkout master')
@ -96,9 +97,7 @@ fn main() {
} }
fn exec(s string) string { fn exec(s string) string {
e := os.exec(s) or { e := os.exec(s) or { panic(err) }
panic(err)
}
return e.output.trim_right('\r\n') return e.output.trim_right('\r\n')
} }
@ -112,7 +111,7 @@ fn measure(cmd string, description string) int {
println(' Building...') println(' Building...')
mut runs := []int{} mut runs := []int{}
for r in 0 .. 5 { for r in 0 .. 5 {
println(' Sample ${r+1}/5') println(' Sample ${r + 1}/5')
sw := time.new_stopwatch({}) sw := time.new_stopwatch({})
exec(cmd) exec(cmd)
runs << int(sw.elapsed().milliseconds()) runs << int(sw.elapsed().milliseconds())

View File

@ -12,21 +12,20 @@ pub fn set_verbose(on bool) {
// but V does not have globals normally. // but V does not have globals normally.
if on { if on {
os.setenv('VERBOSE', '1', true) os.setenv('VERBOSE', '1', true)
} } else {
else {
os.unsetenv('VERBOSE') os.unsetenv('VERBOSE')
} }
} }
pub fn cprintln(message string) { pub fn cprintln(message string) {
mut omessage := message mut omessage := message
omessage = if term_colors { term.green(omessage) } else { omessage } omessage = if scripting.term_colors { term.green(omessage) } else { omessage }
println(omessage) println(omessage)
} }
pub fn verbose_trace(label string, message string) { pub fn verbose_trace(label string, message string) {
if os.getenv('VERBOSE').len > 0 { if os.getenv('VERBOSE').len > 0 {
slabel := 'scripting.${label}' slabel := 'scripting.$label'
cprintln('# ${slabel:-25s} : $message') cprintln('# ${slabel:-25s} : $message')
} }
} }
@ -54,9 +53,9 @@ pub fn rmrf(path string) {
verbose_trace(@FN, 'rm -rf $path') verbose_trace(@FN, 'rm -rf $path')
if os.exists(path) { if os.exists(path) {
if os.is_dir(path) { if os.is_dir(path) {
os.rmdir_all(path) os.rmdir_all(path) or { panic(err) }
}else{ } else {
os.rm(path) os.rm(path) or { panic(err) }
} }
} }
} }
@ -97,7 +96,7 @@ pub fn exit_0_status(cmd string) bool {
return false return false
} }
pub fn tool_must_exist (toolcmd string) { pub fn tool_must_exist(toolcmd string) {
verbose_trace(@FN, toolcmd) verbose_trace(@FN, toolcmd)
if exit_0_status('type $toolcmd') { if exit_0_status('type $toolcmd') {
return return

View File

@ -210,7 +210,7 @@ pub fn (mut ts TestSession) test() {
// cleanup generated .tmp.c files after successfull tests: // cleanup generated .tmp.c files after successfull tests:
if ts.benchmark.nfail == 0 { if ts.benchmark.nfail == 0 {
if ts.rm_binaries { if ts.rm_binaries {
os.rmdir_all(ts.vtmp_dir) os.rmdir_all(ts.vtmp_dir) or { panic(err) }
} }
} }
} }
@ -241,7 +241,7 @@ fn worker_trunner(mut p sync.PoolProcessor, idx int, thread_id int) voidptr {
generated_binary_fpath := os.join_path(tmpd, generated_binary_fname) generated_binary_fpath := os.join_path(tmpd, generated_binary_fname)
if os.exists(generated_binary_fpath) { if os.exists(generated_binary_fpath) {
if ts.rm_binaries { if ts.rm_binaries {
os.rm(generated_binary_fpath) os.rm(generated_binary_fpath) or { panic(err) }
} }
} }
mut cmd_options := [ts.vargs] mut cmd_options := [ts.vargs]
@ -294,7 +294,7 @@ fn worker_trunner(mut p sync.PoolProcessor, idx int, thread_id int) voidptr {
} }
if os.exists(generated_binary_fpath) { if os.exists(generated_binary_fpath) {
if ts.rm_binaries { if ts.rm_binaries {
os.rm(generated_binary_fpath) os.rm(generated_binary_fpath) or { panic(err) }
} }
} }
return sync.no_result return sync.no_result
@ -422,7 +422,7 @@ pub fn header(msg string) {
pub fn setup_new_vtmp_folder() string { pub fn setup_new_vtmp_folder() string {
now := time.sys_mono_now() now := time.sys_mono_now()
new_vtmp_dir := os.join_path(os.temp_dir(), 'v', 'test_session_$now') new_vtmp_dir := os.join_path(os.temp_dir(), 'v', 'test_session_$now')
os.mkdir_all(new_vtmp_dir) os.mkdir_all(new_vtmp_dir) or { panic(err) }
os.setenv('VTMP', new_vtmp_dir, true) os.setenv('VTMP', new_vtmp_dir, true)
return new_vtmp_dir return new_vtmp_dir
} }

View File

@ -28,26 +28,26 @@ fn get_vexe_path() string {
fn new_tdir() string { fn new_tdir() string {
tdir_ := os.join_path(os.temp_dir(), rand.ulid()) tdir_ := os.join_path(os.temp_dir(), rand.ulid())
if os.exists(tdir_) { if os.exists(tdir_) {
os.rmdir(tdir_) os.rmdir(tdir_) or { panic(err) }
} }
os.mkdir(tdir_) os.mkdir(tdir_) or { panic(err) }
C.atexit(cleanup_tdir) C.atexit(cleanup_tdir)
return tdir_ return tdir_
} }
fn cleanup_tdir() { fn cleanup_tdir() {
println('... removing tdir: $tdir') println('... removing tdir: $tdir')
os.rmdir_all(tdir) os.rmdir_all(tdir) or { panic(err) }
} }
fn main() { fn main() {
println('> vroot: $vroot | vexe: $vexe | tdir: $tdir') println('> vroot: $vroot | vexe: $vexe | tdir: $tdir')
ok_fpath := os.join_path(tdir, 'single_test.v') ok_fpath := os.join_path(tdir, 'single_test.v')
os.write_file(ok_fpath, 'fn test_ok(){ assert true }') os.write_file(ok_fpath, 'fn test_ok(){ assert true }') ?
check_ok('"$vexe" $ok_fpath') check_ok('"$vexe" $ok_fpath')
check_ok('"$vexe" test $ok_fpath') check_ok('"$vexe" test $ok_fpath')
fail_fpath := os.join_path(tdir, 'failing_test.v') fail_fpath := os.join_path(tdir, 'failing_test.v')
os.write_file(fail_fpath, 'fn test_fail(){ assert 1 == 2 }') os.write_file(fail_fpath, 'fn test_fail(){ assert 1 == 2 }') ?
check_fail('"$vexe" $fail_fpath') check_fail('"$vexe" $fail_fpath')
check_fail('"$vexe" test $fail_fpath') check_fail('"$vexe" test $fail_fpath')
check_fail('"$vexe" test $tdir') check_fail('"$vexe" test $tdir')

View File

@ -68,7 +68,6 @@ fn (context Context) file2v(bname string, fbytes []byte, bn_max int) string {
sb.write('$b, ') sb.write('$b, ')
line_len += b.len + 2 line_len += b.len + 2
} }
} }
sb.write(']!\n') sb.write(']!\n')
return sb.str() return sb.str()
@ -76,8 +75,8 @@ fn (context Context) file2v(bname string, fbytes []byte, bn_max int) string {
fn (context Context) bname_and_bytes(file string) ?(string, []byte) { fn (context Context) bname_and_bytes(file string) ?(string, []byte) {
fname := os.file_name(file) fname := os.file_name(file)
fname_escpaed := fname.replace_each(['.', '_', '-', '_']) fname_escaped := fname.replace_each(['.', '_', '-', '_'])
byte_name := '$context.prefix$fname_escpaed'.to_lower() byte_name := '$context.prefix$fname_escaped'.to_lower()
fbytes := os.read_bytes(file) or { return error('Error: $err') } fbytes := os.read_bytes(file) or { return error('Error: $err') }
return byte_name, fbytes return byte_name, fbytes
} }
@ -131,12 +130,12 @@ fn main() {
} }
max_bname := context.max_bname_len(file_byte_map.keys()) max_bname := context.max_bname_len(file_byte_map.keys())
if context.write_file.len > 0 { if context.write_file.len > 0 {
mut out_file := os.create(context.write_file) or { panic(err) } mut out_file := os.create(context.write_file) ?
out_file.write_str(context.header()) out_file.write_str(context.header()) ?
for bname, fbytes in file_byte_map { for bname, fbytes in file_byte_map {
out_file.write_str(context.file2v(bname, fbytes, max_bname)) out_file.write_str(context.file2v(bname, fbytes, max_bname)) ?
} }
out_file.write_str(context.footer()) out_file.write_str(context.footer()) ?
} else { } else {
print(context.header()) print(context.header())
for bname, fbytes in file_byte_map { for bname, fbytes in file_byte_map {

View File

@ -55,9 +55,14 @@ fn main() {
// //
tpath := os.join_path(session.vtmp_dir, texe) tpath := os.join_path(session.vtmp_dir, texe)
if tname in tools_in_subfolders { if tname in tools_in_subfolders {
os.mv_by_cp(tpath, os.join_path(tfolder, tname, texe)) os.mv_by_cp(tpath, os.join_path(tfolder, tname, texe)) or { panic(err) }
continue
}
os.mv_by_cp(tpath, os.join_path(tfolder, texe)) or {
if !err.contains('vbuild-tools') {
eprintln(err)
}
continue continue
} }
os.mv_by_cp(tpath, os.join_path(tfolder, texe))
} }
} }

View File

@ -58,7 +58,7 @@ fn (c &Create) write_vmod(new bool) {
cerror(err) cerror(err)
exit(1) exit(1)
} }
vmod.write_str(vmod_content(c.name, c.description)) vmod.write_str(vmod_content(c.name, c.description)) or { panic(err) }
vmod.close() vmod.close()
} }
@ -67,12 +67,12 @@ fn (c &Create) write_main(new bool) {
return return
} }
main_path := if new { '$c.name/${c.name}.v' } else { '${c.name}.v' } main_path := if new { '$c.name/${c.name}.v' } else { '${c.name}.v' }
mut main := os.create(main_path) or { mut mainfile := os.create(main_path) or {
cerror(err) cerror(err)
exit(2) exit(2)
} }
main.write_str(main_content()) mainfile.write_str(main_content()) or { panic(err) }
main.close() mainfile.close()
} }
fn (c &Create) create_git_repo(dir string) { fn (c &Create) create_git_repo(dir string) {
@ -87,7 +87,7 @@ fn (c &Create) create_git_repo(dir string) {
// We don't really need a .gitignore, it's just a nice-to-have // We don't really need a .gitignore, it's just a nice-to-have
return return
} }
fl.write_str(gen_gitignore(c.name)) fl.write_str(gen_gitignore(c.name)) or { panic(err) }
fl.close() fl.close()
} }
} }
@ -110,9 +110,7 @@ fn create() {
} }
c.description = os.input('Input your project description: ') c.description = os.input('Input your project description: ')
println('Initialising ...') println('Initialising ...')
os.mkdir(c.name) or { os.mkdir(c.name) or { panic(err) }
panic(err)
}
c.write_vmod(true) c.write_vmod(true)
c.write_main(true) c.write_main(true)
c.create_git_repo(c.name) c.create_git_repo(c.name)

View File

@ -126,7 +126,7 @@ fn (vd VDoc) render_search_index(out Output) {
js_search_index.writeln('];') js_search_index.writeln('];')
js_search_data.writeln('];') js_search_data.writeln('];')
out_file_path := os.join_path(out.path, 'search_index.js') out_file_path := os.join_path(out.path, 'search_index.js')
os.write_file(out_file_path, js_search_index.str() + js_search_data.str()) os.write_file(out_file_path, js_search_index.str() + js_search_data.str()) or { panic(err) }
} }
fn (mut vd VDoc) render_static_html(out Output) { fn (mut vd VDoc) render_static_html(out Output) {
@ -162,7 +162,7 @@ fn (vd VDoc) get_resource(name string, out Output) string {
output_path := os.join_path(out.path, name) output_path := os.join_path(out.path, name)
if !os.exists(output_path) { if !os.exists(output_path) {
println('Generating $out.typ in "$output_path"') println('Generating $out.typ in "$output_path"')
os.write_file(output_path, res) os.write_file(output_path, res) or { panic(err) }
} }
return name return name
} }

View File

@ -162,7 +162,7 @@ fn (vd VDoc) work_processor(mut work sync.Channel, mut wg sync.WaitGroup) {
file_name, content := vd.render_doc(pdoc.d, pdoc.out) file_name, content := vd.render_doc(pdoc.d, pdoc.out)
output_path := os.join_path(pdoc.out.path, file_name) output_path := os.join_path(pdoc.out.path, file_name)
println('Generating $pdoc.out.typ in "$output_path"') println('Generating $pdoc.out.typ in "$output_path"')
os.write_file(output_path, content) os.write_file(output_path, content) or { panic(err) }
} }
wg.done() wg.done()
} }
@ -358,7 +358,7 @@ fn (mut vd VDoc) generate_docs_from_file() {
os.mkdir(out.path) or { panic(err) } os.mkdir(out.path) or { panic(err) }
} else { } else {
for fname in css_js_assets { for fname in css_js_assets {
os.rm(os.join_path(out.path, fname)) os.rm(os.join_path(out.path, fname)) or { panic(err) }
} }
} }
} }
@ -376,7 +376,7 @@ fn (mut vd VDoc) generate_docs_from_file() {
for favicon in favicons { for favicon in favicons {
favicon_path := os.join_path(favicons_path, favicon) favicon_path := os.join_path(favicons_path, favicon)
destination_path := os.join_path(out.path, favicon) destination_path := os.join_path(out.path, favicon)
os.cp(favicon_path, destination_path) os.cp(favicon_path, destination_path) or { panic(err) }
} }
} }
} }

View File

@ -176,7 +176,7 @@ fn (foptions &FormatOptions) format_file(file string) {
file_name := os.file_name(file) file_name := os.file_name(file)
ulid := rand.ulid() ulid := rand.ulid()
vfmt_output_path := os.join_path(vtmp_folder, 'vfmt_${ulid}_$file_name') vfmt_output_path := os.join_path(vtmp_folder, 'vfmt_${ulid}_$file_name')
os.write_file(vfmt_output_path, formatted_content) os.write_file(vfmt_output_path, formatted_content) or { panic(err) }
if foptions.is_verbose { if foptions.is_verbose {
eprintln('fmt.fmt worked and $formatted_content.len bytes were written to $vfmt_output_path .') eprintln('fmt.fmt worked and $formatted_content.len bytes were written to $vfmt_output_path .')
} }
@ -258,7 +258,8 @@ fn (foptions &FormatOptions) post_process_file(file string, formatted_file_path
} }
fn (f FormatOptions) str() string { fn (f FormatOptions) str() string {
return 'FormatOptions{ is_l: $f.is_l, is_w: $f.is_w, is_diff: $f.is_diff, is_verbose: $f.is_verbose,' + return
'FormatOptions{ is_l: $f.is_l, is_w: $f.is_w, is_diff: $f.is_diff, is_verbose: $f.is_verbose,' +
' is_all: $f.is_all, is_worker: $f.is_worker, is_debug: $f.is_debug, is_noerror: $f.is_noerror,' + ' is_all: $f.is_all, is_worker: $f.is_worker, is_debug: $f.is_debug, is_noerror: $f.is_noerror,' +
' is_verify: $f.is_verify" }' ' is_verify: $f.is_verify" }'
} }

View File

@ -19,15 +19,15 @@ const (
supported_vcs_folders = ['.git', '.hg'] supported_vcs_folders = ['.git', '.hg']
supported_vcs_update_cmds = { supported_vcs_update_cmds = {
'git': 'git pull' 'git': 'git pull'
'hg': 'hg pull --update' 'hg': 'hg pull --update'
} }
supported_vcs_install_cmds = { supported_vcs_install_cmds = {
'git': 'git clone --depth=1' 'git': 'git clone --depth=1'
'hg': 'hg clone' 'hg': 'hg clone'
} }
supported_vcs_outdated_steps = { supported_vcs_outdated_steps = {
'git': ['git fetch', 'git rev-parse @', 'git rev-parse @{u}'] 'git': ['git fetch', 'git rev-parse @', 'git rev-parse @{u}']
'hg': ['hg incoming'] 'hg': ['hg incoming']
} }
) )
@ -71,9 +71,7 @@ fn main() {
'install' { 'install' {
if module_names.len == 0 && os.exists('./v.mod') { if module_names.len == 0 && os.exists('./v.mod') {
println('Detected v.mod file inside the project directory. Using it...') println('Detected v.mod file inside the project directory. Using it...')
manifest := vmod.from_file('./v.mod') or { manifest := vmod.from_file('./v.mod') or { panic(err) }
panic(err)
}
module_names = manifest.dependencies module_names = manifest.dependencies
} }
vpm_install(module_names) vpm_install(module_names)
@ -227,15 +225,11 @@ fn vpm_update(m []string) {
} }
mut errors := 0 mut errors := 0
for name in module_names { for name in module_names {
final_module_path := valid_final_path_of_existing_module(name) or { final_module_path := valid_final_path_of_existing_module(name) or { continue }
continue
}
os.chdir(final_module_path) os.chdir(final_module_path)
println('Updating module "$name"...') println('Updating module "$name"...')
verbose_println(' work folder: $final_module_path') verbose_println(' work folder: $final_module_path')
vcs := vcs_used_in_dir(final_module_path) or { vcs := vcs_used_in_dir(final_module_path) or { continue }
continue
}
vcs_cmd := supported_vcs_update_cmds[vcs[0]] vcs_cmd := supported_vcs_update_cmds[vcs[0]]
verbose_println(' command: $vcs_cmd') verbose_println(' command: $vcs_cmd')
vcs_res := os.exec('$vcs_cmd') or { vcs_res := os.exec('$vcs_cmd') or {
@ -265,13 +259,9 @@ fn get_outdated() ?[]string {
module_names := get_installed_modules() module_names := get_installed_modules()
mut outdated := []string{} mut outdated := []string{}
for name in module_names { for name in module_names {
final_module_path := valid_final_path_of_existing_module(name) or { final_module_path := valid_final_path_of_existing_module(name) or { continue }
continue
}
os.chdir(final_module_path) os.chdir(final_module_path)
vcs := vcs_used_in_dir(final_module_path) or { vcs := vcs_used_in_dir(final_module_path) or { continue }
continue
}
vcs_cmd_steps := supported_vcs_outdated_steps[vcs[0]] vcs_cmd_steps := supported_vcs_outdated_steps[vcs[0]]
mut outputs := []string{} mut outputs := []string{}
for step in vcs_cmd_steps { for step in vcs_cmd_steps {
@ -296,9 +286,7 @@ fn get_outdated() ?[]string {
} }
fn vpm_upgrade() { fn vpm_upgrade() {
outdated := get_outdated() or { outdated := get_outdated() or { exit(1) }
exit(1)
}
if outdated.len > 0 { if outdated.len > 0 {
vpm_update(outdated) vpm_update(outdated)
} else { } else {
@ -307,9 +295,7 @@ fn vpm_upgrade() {
} }
fn vpm_outdated() { fn vpm_outdated() {
outdated := get_outdated() or { outdated := get_outdated() or { exit(1) }
exit(1)
}
if outdated.len > 0 { if outdated.len > 0 {
println('Outdated modules:') println('Outdated modules:')
for m in outdated { for m in outdated {
@ -342,18 +328,16 @@ fn vpm_remove(module_names []string) {
exit(2) exit(2)
} }
for name in module_names { for name in module_names {
final_module_path := valid_final_path_of_existing_module(name) or { final_module_path := valid_final_path_of_existing_module(name) or { continue }
continue
}
println('Removing module "$name"...') println('Removing module "$name"...')
verbose_println('removing folder $final_module_path') verbose_println('removing folder $final_module_path')
os.rmdir_all(final_module_path) os.rmdir_all(final_module_path) or { panic(err) }
// delete author directory if it is empty // delete author directory if it is empty
author := name.split('.')[0] author := name.split('.')[0]
author_dir := os.real_path(os.join_path(settings.vmodules_path, author)) author_dir := os.real_path(os.join_path(settings.vmodules_path, author))
if os.is_dir_empty(author_dir) { if os.is_dir_empty(author_dir) {
verbose_println('removing author folder $author_dir') verbose_println('removing author folder $author_dir')
os.rmdir(author_dir) os.rmdir(author_dir) or { panic(err) }
} }
} }
} }
@ -380,9 +364,7 @@ fn valid_final_path_of_existing_module(name string) ?string {
fn ensure_vmodules_dir_exist() { fn ensure_vmodules_dir_exist() {
if !os.is_dir(settings.vmodules_path) { if !os.is_dir(settings.vmodules_path) {
println('Creating $settings.vmodules_path/ ...') println('Creating $settings.vmodules_path/ ...')
os.mkdir(settings.vmodules_path) or { os.mkdir(settings.vmodules_path) or { panic(err) }
panic(err)
}
} }
} }
@ -405,9 +387,7 @@ fn vcs_used_in_dir(dir string) ?[]string {
} }
fn get_installed_modules() []string { fn get_installed_modules() []string {
dirs := os.ls(settings.vmodules_path) or { dirs := os.ls(settings.vmodules_path) or { return [] }
return []
}
mut modules := []string{} mut modules := []string{}
for dir in dirs { for dir in dirs {
adir := os.join_path(settings.vmodules_path, dir) adir := os.join_path(settings.vmodules_path, dir)
@ -420,13 +400,9 @@ fn get_installed_modules() []string {
continue continue
} }
author := dir author := dir
mods := os.ls(adir) or { mods := os.ls(adir) or { continue }
continue
}
for m in mods { for m in mods {
vcs_used_in_dir(os.join_path(adir, m)) or { vcs_used_in_dir(os.join_path(adir, m)) or { continue }
continue
}
modules << '${author}.$m' modules << '${author}.$m'
} }
} }
@ -435,9 +411,7 @@ fn get_installed_modules() []string {
fn get_all_modules() []string { fn get_all_modules() []string {
url := get_working_server_url() url := get_working_server_url()
r := http.get(url) or { r := http.get(url) or { panic(err) }
panic(err)
}
if r.status_code != 200 { if r.status_code != 200 {
println('Failed to search vpm.vlang.io. Status code: $r.status_code') println('Failed to search vpm.vlang.io. Status code: $r.status_code')
exit(1) exit(1)
@ -476,9 +450,7 @@ fn resolve_dependencies(name string, module_path string, module_names []string)
if !os.exists(vmod_path) { if !os.exists(vmod_path) {
return return
} }
data := os.read_file(vmod_path) or { data := os.read_file(vmod_path) or { return }
return
}
vmod := parse_vmod(data) vmod := parse_vmod(data)
mut deps := []string{} mut deps := []string{}
// filter out dependencies that were already specified by the user // filter out dependencies that were already specified by the user
@ -497,14 +469,12 @@ fn resolve_dependencies(name string, module_path string, module_names []string)
fn parse_vmod(data string) Vmod { fn parse_vmod(data string) Vmod {
keys := ['name', 'version', 'deps'] keys := ['name', 'version', 'deps']
mut m := { mut m := {
'name': '' 'name': ''
'version': '' 'version': ''
'deps': '' 'deps': ''
} }
for key in keys { for key in keys {
mut key_index := data.index('$key:') or { mut key_index := data.index('$key:') or { continue }
continue
}
key_index += key.len + 1 key_index += key.len + 1
m[key] = data[key_index..data.index_after('\n', key_index)].trim_space().replace("'", m[key] = data[key_index..data.index_after('\n', key_index)].trim_space().replace("'",
'').replace('[', '').replace(']', '') '').replace('[', '').replace(']', '')
@ -519,7 +489,11 @@ fn parse_vmod(data string) Vmod {
} }
fn get_working_server_url() string { fn get_working_server_url() string {
server_urls := if settings.server_urls.len > 0 { settings.server_urls } else { default_vpm_server_urls } server_urls := if settings.server_urls.len > 0 {
settings.server_urls
} else {
default_vpm_server_urls
}
for url in server_urls { for url in server_urls {
verbose_println('Trying server url: $url') verbose_println('Trying server url: $url')
http.head(url) or { http.head(url) or {
@ -572,13 +546,11 @@ fn get_module_meta_info(name string) ?Mod {
continue continue
} }
if r.status_code == 404 || r.text.contains('404') { if r.status_code == 404 || r.text.contains('404') {
errors << errors << 'Skipping module "$name", since $server_url reported that "$name" does not exist.'
'Skipping module "$name", since $server_url reported that "$name" does not exist.'
continue continue
} }
if r.status_code != 200 { if r.status_code != 200 {
errors << errors << 'Skipping module "$name", since $server_url responded with $r.status_code http status code. Please try again later.'
'Skipping module "$name", since $server_url responded with $r.status_code http status code. Please try again later.'
continue continue
} }
s := r.text s := r.text

View File

@ -11,10 +11,10 @@ import v.util
struct Repl { struct Repl {
mut: mut:
readline readline.Readline readline readline.Readline
indent int // indentation level indent int // indentation level
in_func bool // are we inside a new custom user function in_func bool // are we inside a new custom user function
line string // the current line entered by the user line string // the current line entered by the user
// //
modules []string // all the import modules modules []string // all the import modules
includes []string // all the #include statements includes []string // all the #include statements
@ -109,21 +109,7 @@ fn run_repl(workdir string, vrepl_prefix string) {
if !is_stdin_a_pipe { if !is_stdin_a_pipe {
println('') println('')
} }
os.rm(file) cleanup_files([file, temp_file])
os.rm(temp_file)
$if windows {
os.rm(file[..file.len - 2] + '.exe')
os.rm(temp_file[..temp_file.len - 2] + '.exe')
$if msvc {
os.rm(file[..file.len - 2] + '.ilk')
os.rm(file[..file.len - 2] + '.pdb')
os.rm(temp_file[..temp_file.len - 2] + '.ilk')
os.rm(temp_file[..temp_file.len - 2] + '.pdb')
}
} $else {
os.rm(file[..file.len - 2])
os.rm(temp_file[..temp_file.len - 2])
}
} }
mut r := new_repl() mut r := new_repl()
vexe := os.getenv('VEXE') vexe := os.getenv('VEXE')
@ -198,7 +184,7 @@ fn run_repl(workdir string, vrepl_prefix string) {
} }
if r.line.starts_with('print') { if r.line.starts_with('print') {
source_code := r.current_source_code(false) + '\n$r.line\n' source_code := r.current_source_code(false) + '\n$r.line\n'
os.write_file(file, source_code) os.write_file(file, source_code) or { panic(err) }
s := os.exec('"$vexe" -repl run "$file"') or { s := os.exec('"$vexe" -repl run "$file"') or {
rerror(err) rerror(err)
return return
@ -208,7 +194,7 @@ fn run_repl(workdir string, vrepl_prefix string) {
mut temp_line := r.line mut temp_line := r.line
mut temp_flag := false mut temp_flag := false
func_call := r.function_call(r.line) func_call := r.function_call(r.line)
filter_line := r.line.replace(r.line.find_between("\'", "\'"), '').replace(r.line.find_between('"', filter_line := r.line.replace(r.line.find_between("'", "'"), '').replace(r.line.find_between('"',
'"'), '') '"'), '')
possible_statement_patterns := [ possible_statement_patterns := [
'=', '=',
@ -268,7 +254,7 @@ fn run_repl(workdir string, vrepl_prefix string) {
} }
temp_source_code = r.current_source_code(true) + '\n$temp_line\n' temp_source_code = r.current_source_code(true) + '\n$temp_line\n'
} }
os.write_file(temp_file, temp_source_code) os.write_file(temp_file, temp_source_code) or { panic(err) }
s := os.exec('"$vexe" -repl run "$temp_file"') or { s := os.exec('"$vexe" -repl run "$temp_file"') or {
rerror(err) rerror(err)
return return
@ -355,3 +341,18 @@ fn (mut r Repl) get_one_line(prompt string) ?string {
rline := r.readline.read_line(prompt) or { return none } rline := r.readline.read_line(prompt) or { return none }
return rline return rline
} }
fn cleanup_files(files []string) {
for file in files {
os.rm(file) or { }
$if windows {
os.rm(file[..file.len - 2] + '.exe') or { }
$if msvc {
os.rm(file[..file.len - 2] + '.ilk') or { }
os.rm(file[..file.len - 2] + '.pdb') or { }
}
} $else {
os.rm(file[..file.len - 2]) or { }
}
}
}

View File

@ -4,6 +4,7 @@ import v.pref
$if windows { $if windows {
$if tinyc { $if tinyc {
#flag -lAdvapi32 #flag -lAdvapi32
#flag -lUser32 #flag -lUser32
} }
} }
@ -19,20 +20,16 @@ fn main() {
fn setup_symlink(vexe string) { fn setup_symlink(vexe string) {
link_dir := '/usr/local/bin' link_dir := '/usr/local/bin'
if !os.exists(link_dir) { if !os.exists(link_dir) {
os.mkdir_all(link_dir) os.mkdir_all(link_dir) or { panic(err) }
} }
mut link_path := link_dir + '/v' mut link_path := link_dir + '/v'
mut ret := os.exec('ln -sf $vexe $link_path') or { mut ret := os.exec('ln -sf $vexe $link_path') or { panic(err) }
panic(err)
}
if ret.exit_code == 0 { if ret.exit_code == 0 {
println('Symlink "$link_path" has been created') println('Symlink "$link_path" has been created')
} else if os.system("uname -o | grep -q \'[A/a]ndroid\'") == 0 { } else if os.system("uname -o | grep -q '[A/a]ndroid'") == 0 {
println('Failed to create symlink "$link_path". Trying again with Termux path for Android.') println('Failed to create symlink "$link_path". Trying again with Termux path for Android.')
link_path = '/data/data/com.termux/files/usr/bin/v' link_path = '/data/data/com.termux/files/usr/bin/v'
ret = os.exec('ln -sf $vexe $link_path') or { ret = os.exec('ln -sf $vexe $link_path') or { panic(err) }
panic(err)
}
if ret.exit_code == 0 { if ret.exit_code == 0 {
println('Symlink "$link_path" has been created') println('Symlink "$link_path" has been created')
} else { } else {
@ -52,9 +49,9 @@ fn setup_symlink_windows(vexe string) {
vsymlinkdir := os.join_path(vdir, '.bin') vsymlinkdir := os.join_path(vdir, '.bin')
mut vsymlink := os.join_path(vsymlinkdir, 'v.exe') mut vsymlink := os.join_path(vsymlinkdir, 'v.exe')
if !os.exists(vsymlinkdir) { if !os.exists(vsymlinkdir) {
os.mkdir_all(vsymlinkdir) // will panic if fails os.mkdir_all(vsymlinkdir) or { panic(err) } // will panic if fails
} else { } else {
os.rm(vsymlink) os.rm(vsymlink) or { panic(err) }
} }
// First, try to create a native symlink at .\.bin\v.exe // First, try to create a native symlink at .\.bin\v.exe
os.symlink(vsymlink, vexe) or { os.symlink(vsymlink, vexe) or {
@ -64,9 +61,9 @@ fn setup_symlink_windows(vexe string) {
eprintln('Creating a batch file instead...') eprintln('Creating a batch file instead...')
vsymlink = os.join_path(vsymlinkdir, 'v.bat') vsymlink = os.join_path(vsymlinkdir, 'v.bat')
if os.exists(vsymlink) { if os.exists(vsymlink) {
os.rm(vsymlink) os.rm(vsymlink) or { panic(err) }
} }
os.write_file(vsymlink, '@echo off\n$vexe %*') os.write_file(vsymlink, '@echo off\n$vexe %*') or { panic(err) }
eprintln('$vsymlink file written.') eprintln('$vsymlink file written.')
} }
if !os.exists(vsymlink) { if !os.exists(vsymlink) {
@ -83,9 +80,7 @@ fn setup_symlink_windows(vexe string) {
// C.RegCloseKey(reg_sys_env_handle) // C.RegCloseKey(reg_sys_env_handle)
// } // }
// if the above succeeded, and we cannot get the value, it may simply be empty // if the above succeeded, and we cannot get the value, it may simply be empty
sys_env_path := get_reg_value(reg_sys_env_handle, 'Path') or { sys_env_path := get_reg_value(reg_sys_env_handle, 'Path') or { '' }
''
}
current_sys_paths := sys_env_path.split(os.path_delimiter).map(it.trim('/$os.path_separator')) current_sys_paths := sys_env_path.split(os.path_delimiter).map(it.trim('/$os.path_separator'))
mut new_paths := [vsymlinkdir] mut new_paths := [vsymlinkdir]
for p in current_sys_paths { for p in current_sys_paths {
@ -171,8 +166,7 @@ fn set_reg_value(reg_key voidptr, key string, value string) ?bool {
// letting them know that the system environment has changed and should be reloaded // letting them know that the system environment has changed and should be reloaded
fn send_setting_change_msg(message_data string) ?bool { fn send_setting_change_msg(message_data string) ?bool {
$if windows { $if windows {
if C.SendMessageTimeout(os.hwnd_broadcast, os.wm_settingchange, 0, message_data.to_wide(), os.smto_abortifhung, 5000, 0) == if C.SendMessageTimeout(os.hwnd_broadcast, os.wm_settingchange, 0, message_data.to_wide(), os.smto_abortifhung, 5000, 0) == 0 {
0 {
return error('Could not broadcast WM_SETTINGCHANGE') return error('Could not broadcast WM_SETTINGCHANGE')
} }
return true return true

View File

@ -108,9 +108,9 @@ fn (app App) show_current_v_version() {
fn (app App) backup(file string) { fn (app App) backup(file string) {
backup_file := '${file}_old.exe' backup_file := '${file}_old.exe'
if os.exists(backup_file) { if os.exists(backup_file) {
os.rm(backup_file) os.rm(backup_file) or { panic(err) }
} }
os.mv(file, backup_file) os.mv(file, backup_file) or { panic(err) }
} }
fn (app App) git_command(command string) { fn (app App) git_command(command string) {

View File

@ -7,7 +7,7 @@ fn main() {
mut cm := vcache.new_cache_manager([]) mut cm := vcache.new_cache_manager([])
cpath := cm.basepath cpath := cm.basepath
if os.exists(cpath) && os.is_dir(cpath) { if os.exists(cpath) && os.is_dir(cpath) {
os.rmdir_all(cpath) os.rmdir_all(cpath) or { }
} }
println('V cache folder $cpath was wiped.') println('V cache folder $cpath was wiped.')
} }

View File

@ -3,12 +3,14 @@ import io
fn main() { fn main() {
// Make a new connection // Make a new connection
mut conn := net.dial_tcp('google.com:80')? mut conn := net.dial_tcp('google.com:80') ?
defer { conn.close() } defer {
conn.close() or { }
}
// Simple http HEAD request for a file // Simple http HEAD request for a file
conn.write_str('HEAD /index.html HTTP/1.0\r\n\r\n')? conn.write_str('HEAD /index.html HTTP/1.0\r\n\r\n') ?
// Read all the data that is waiting // Read all the data that is waiting
result := io.read_all(reader: conn)? result := io.read_all(reader: conn) ?
// Cast to string and print result // Cast to string and print result
println(result.bytestr()) println(result.bytestr())
} }

View File

@ -35,67 +35,63 @@ const (
f_0 = 0.0 f_0 = 0.0
) )
/***************************** 3D Vector utility struct **********************/ //**************************** 3D Vector utility struct *********************
struct Vec { struct Vec {
mut: mut:
x f64 = 0.0 x f64 = 0.0
y f64 = 0.0 y f64 = 0.0
z f64 = 0.0 z f64 = 0.0
} }
[inline] [inline]
fn (v Vec) + (b Vec) Vec{ fn (v Vec) + (b Vec) Vec {
return Vec{ v.x + b.x , v.y + b.y, v.z + b.z } return Vec{v.x + b.x, v.y + b.y, v.z + b.z}
} }
[inline] [inline]
fn (v Vec) - (b Vec) Vec{ fn (v Vec) - (b Vec) Vec {
return Vec{ v.x - b.x , v.y - b.y, v.z - b.z } return Vec{v.x - b.x, v.y - b.y, v.z - b.z}
} }
[inline] [inline]
fn (v Vec) * (b Vec) Vec{ fn (v Vec) * (b Vec) Vec {
return Vec{ v.x * b.x , v.y * b.y, v.z * b.z } return Vec{v.x * b.x, v.y * b.y, v.z * b.z}
} }
[inline] [inline]
fn (v Vec) dot (b Vec) f64{ fn (v Vec) dot(b Vec) f64 {
return v.x * b.x + v.y * b.y + v.z * b.z return v.x * b.x + v.y * b.y + v.z * b.z
} }
[inline] [inline]
fn (v Vec) mult_s (b f64) Vec{ fn (v Vec) mult_s(b f64) Vec {
return Vec{ v.x * b , v.y * b, v.z * b } return Vec{v.x * b, v.y * b, v.z * b}
} }
[inline] [inline]
fn (v Vec) cross (b Vec) Vec{ fn (v Vec) cross(b Vec) Vec {
return Vec{ return Vec{v.y * b.z - v.z * b.y, v.z * b.x - v.x * b.z, v.x * b.y - v.y * b.x}
v.y * b.z - v.z * b.y,
v.z * b.x - v.x * b.z,
v.x * b.y - v.y * b.x
}
} }
[inline] [inline]
fn (v Vec) norm () Vec { fn (v Vec) norm() Vec {
tmp_norm := 1.0 / math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z) tmp_norm := 1.0 / math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z)
return Vec{ v.x * tmp_norm , v.y * tmp_norm, v.z * tmp_norm } return Vec{v.x * tmp_norm, v.y * tmp_norm, v.z * tmp_norm}
} }
/*********************************Image***************************************/ //********************************Image**************************************
struct Image { struct Image {
width int width int
height int height int
data &Vec data &Vec
} }
fn new_image(w int, h int) Image { fn new_image(w int, h int) Image {
vecsize := int(sizeof(Vec)) vecsize := int(sizeof(Vec))
return Image{ return Image{
width: w, width: w
height: h, height: h
data: &Vec(vcalloc(vecsize*w*h)) data: &Vec(vcalloc(vecsize * w * h))
} }
} }
@ -103,19 +99,19 @@ fn new_image(w int, h int) Image {
fn (image Image) save_as_ppm(file_name string) { fn (image Image) save_as_ppm(file_name string) {
npixels := image.width * image.height npixels := image.width * image.height
mut f_out := os.create(file_name) or { panic(err) } mut f_out := os.create(file_name) or { panic(err) }
f_out.writeln('P3') f_out.writeln('P3') or { panic(err) }
f_out.writeln('${image.width} ${image.height}') f_out.writeln('$image.width $image.height') or { panic(err) }
f_out.writeln('255') f_out.writeln('255') or { panic(err) }
for i in 0..npixels { for i in 0 .. npixels {
c_r := to_int(unsafe{image.data[i]}.x) c_r := to_int(unsafe { image.data[i] }.x)
c_g := to_int(unsafe{image.data[i]}.y) c_g := to_int(unsafe { image.data[i] }.y)
c_b := to_int(unsafe{image.data[i]}.z) c_b := to_int(unsafe { image.data[i] }.z)
f_out.write_str('$c_r $c_g $c_b ') f_out.write_str('$c_r $c_g $c_b ') or { panic(err) }
} }
f_out.close() f_out.close()
} }
/*********************************** Ray *************************************/ //********************************** Ray ************************************
struct Ray { struct Ray {
o Vec o Vec
d Vec d Vec
@ -128,19 +124,19 @@ enum Refl_t {
refr refr
} }
/********************************* Sphere ************************************/ //******************************** Sphere ***********************************
struct Sphere { struct Sphere {
rad f64 = 0.0 // radius rad f64 = 0.0 // radius
p Vec // position p Vec // position
e Vec // emission e Vec // emission
c Vec // color c Vec // color
refl Refl_t // reflection type => [diffuse, specular, refractive] refl Refl_t // reflection type => [diffuse, specular, refractive]
} }
fn (sp Sphere) intersect (r Ray) f64 { fn (sp Sphere) intersect(r Ray) f64 {
op := sp.p - r.o // Solve t^2*d.d + 2*t*(o-p).d + (o-p).(o-p)-R^2 = 0 op := sp.p - r.o // Solve t^2*d.d + 2*t*(o-p).d + (o-p).(o-p)-R^2 = 0
b := op.dot(r.d) b := op.dot(r.d)
mut det := b * b - op.dot(op) + sp.rad * sp.rad mut det := b * b - op.dot(op) + sp.rad * sp.rad
if det < 0 { if det < 0 {
return 0 return 0
@ -167,82 +163,181 @@ fn (sp Sphere) intersect (r Ray) f64 {
* The sphere fileds are: Sphere{radius, position, emission, color, material} * The sphere fileds are: Sphere{radius, position, emission, color, material}
******************************************************************************/ ******************************************************************************/
const ( const (
cen = Vec{50, 40.8, -860} // used by scene 1 cen = Vec{50, 40.8, -860} // used by scene 1
spheres = [ spheres = [
[// scene 0 cornnel box [/* scene 0 cornnel box */ Sphere{
Sphere{rad: 1e+5, p: Vec{ 1e+5 +1,40.8,81.6} , e: Vec{} , c: Vec{.75,.25,.25} , refl: .diff},//Left rad: 1e+5
Sphere{rad: 1e+5, p: Vec{-1e+5 +99,40.8,81.6}, e: Vec{} , c: Vec{.25,.25,.75} , refl: .diff},//Rght p: Vec{1e+5 + 1, 40.8, 81.6}
Sphere{rad: 1e+5, p: Vec{50,40.8, 1e+5} , e: Vec{} , c: Vec{.75,.75,.75} , refl: .diff},//Back e: Vec{}
Sphere{rad: 1e+5, p: Vec{50,40.8,-1e+5 +170} , e: Vec{} , c: Vec{} , refl: .diff},//Frnt c: Vec{.75, .25, .25}
Sphere{rad: 1e+5, p: Vec{50, 1e+5, 81.6} , e: Vec{} , c: Vec{.75,.75,.75} , refl: .diff},//Botm refl: .diff
Sphere{rad: 1e+5, p: Vec{50,-1e+5 +81.6,81.6}, e: Vec{} , c: Vec{.75,.75,.75} , refl: .diff},//Top }, /* Left */ Sphere{
Sphere{rad: 16.5, p: Vec{27,16.5,47} , e: Vec{} , c: Vec{1,1,1}.mult_s(.999) , refl: .spec},//Mirr rad: 1e+5
Sphere{rad: 16.5, p: Vec{73,16.5,78} , e: Vec{} , c: Vec{1,1,1}.mult_s(.999) , refl: .refr},//Glas p: Vec{-1e+5 + 99, 40.8, 81.6}
Sphere{rad: 600 , p: Vec{50,681.6-.27,81.6} , e: Vec{12,12,12}, c: Vec{}, refl: .diff} //Lite e: Vec{}
], c: Vec{.25, .25, .75}
refl: .diff
[// scene 1 sunset }, /* Rght */ Sphere{
Sphere{rad: 1600, p: Vec{1.0,0.0,2.0}.mult_s(3000), e: Vec{1.0,.9,.8}.mult_s(1.2e+1*1.56*2) , c: Vec{} , refl: .diff}, // sun rad: 1e+5
Sphere{rad: 1560, p: Vec{1,0,2}.mult_s(3500) , e: Vec{1.0,.5,.05}.mult_s(4.8e+1*1.56*2) , c: Vec{} , refl: .diff}, // horizon sun2 p: Vec{50, 40.8, 1e+5}
Sphere{rad: 10000, p: cen+Vec{0,0,-200}, e: Vec{0.00063842, 0.02001478, 0.28923243}.mult_s(6e-2*8), c: Vec{.7,.7,1}.mult_s(.25), refl: .diff}, // sky e: Vec{}
c: Vec{.75, .75, .75}
Sphere{rad: 100000, p: Vec{50, -100000, 0} , e: Vec{} , c: Vec{.3,.3,.3} , refl: .diff}, // grnd refl: .diff
Sphere{rad: 110000, p: Vec{50, -110048.5, 0} , e: Vec{.9,.5,.05}.mult_s(4) , c: Vec{}, refl: .diff},// horizon brightener }, /* Back */ Sphere{
Sphere{rad: 4e+4 , p: Vec{50, -4e+4-30, -3000}, e: Vec{} , c: Vec{.2,.2,.2} , refl: .diff},// mountains rad: 1e+5
p: Vec{50, 40.8, -1e+5 + 170}
Sphere{rad: 26.5, p: Vec{22,26.5,42}, e: Vec{}, c: Vec{1,1,1}.mult_s(.596) , refl: .spec}, // white Mirr e: Vec{}
Sphere{rad: 13, p: Vec{75,13,82 }, e: Vec{}, c: Vec{.96,.96,.96}.mult_s(.96), refl: .refr},// Glas c: Vec{}
Sphere{rad: 22, p: Vec{87,22,24 }, e: Vec{}, c: Vec{.6,.6,.6}.mult_s(.696) , refl: .refr} // Glas2 refl: .diff
], }, /* Frnt */ Sphere{
rad: 1e+5
p: Vec{50, 1e+5, 81.6}
[// scene 3 Psychedelic e: Vec{}
Sphere{rad: 150, p: Vec{50+75,28,62}, e: Vec{1,1,1}.mult_s(0e-3), c: Vec{1,.9,.8}.mult_s(.93), refl: .refr}, c: Vec{.75, .75, .75}
Sphere{rad: 28 , p: Vec{50+5,-28,62}, e: Vec{1,1,1}.mult_s(1e+1), c: Vec{1,1,1}.mult_s(0) , refl: .diff}, refl: .diff
Sphere{rad: 300, p: Vec{50,28,62} , e: Vec{1,1,1}.mult_s(0e-3), c: Vec{1,1,1}.mult_s(.93) , refl: .spec} }, /* Botm */ Sphere{
] rad: 1e+5
p: Vec{50, -1e+5 + 81.6, 81.6}
] // end of scene array e: Vec{}
c: Vec{.75, .75, .75}
refl: .diff
}, /* Top */ Sphere{
rad: 16.5
p: Vec{27, 16.5, 47}
e: Vec{}
c: Vec{1, 1, 1}.mult_s(.999)
refl: .spec
}, /* Mirr */ Sphere{
rad: 16.5
p: Vec{73, 16.5, 78}
e: Vec{}
c: Vec{1, 1, 1}.mult_s(.999)
refl: .refr
}, /* Glas */ Sphere{
rad: 600
p: Vec{50, 681.6 - .27, 81.6}
e: Vec{12, 12, 12}
c: Vec{}
refl: .diff
} /* Lite */],
[/* scene 1 sunset */ Sphere{
rad: 1600
p: Vec{1.0, 0.0, 2.0}.mult_s(3000)
e: Vec{1.0, .9, .8}.mult_s(1.2e+1 * 1.56 * 2)
c: Vec{}
refl: .diff
}, /* sun */ Sphere{
rad: 1560
p: Vec{1, 0, 2}.mult_s(3500)
e: Vec{1.0, .5, .05}.mult_s(4.8e+1 * 1.56 * 2)
c: Vec{}
refl: .diff
}, /* horizon sun2 */ Sphere{
rad: 10000
p: cen + Vec{0, 0, -200}
e: Vec{0.00063842, 0.02001478, 0.28923243}.mult_s(6e-2 * 8)
c: Vec{.7, .7, 1}.mult_s(.25)
refl: .diff
}, /* sky */ Sphere{
rad: 100000
p: Vec{50, -100000, 0}
e: Vec{}
c: Vec{.3, .3, .3}
refl: .diff
}, /* grnd */ Sphere{
rad: 110000
p: Vec{50, -110048.5, 0}
e: Vec{.9, .5, .05}.mult_s(4)
c: Vec{}
refl: .diff
}, /* horizon brightener */ Sphere{
rad: 4e+4
p: Vec{50, -4e+4 - 30, -3000}
e: Vec{}
c: Vec{.2, .2, .2}
refl: .diff
}, /* mountains */ Sphere{
rad: 26.5
p: Vec{22, 26.5, 42}
e: Vec{}
c: Vec{1, 1, 1}.mult_s(.596)
refl: .spec
}, /* white Mirr */ Sphere{
rad: 13
p: Vec{75, 13, 82}
e: Vec{}
c: Vec{.96, .96, .96}.mult_s(.96)
refl: .refr
}, /* Glas */ Sphere{
rad: 22
p: Vec{87, 22, 24}
e: Vec{}
c: Vec{.6, .6, .6}.mult_s(.696)
refl: .refr
} /* Glas2 */],
[/* scene 3 Psychedelic */ Sphere{
rad: 150
p: Vec{50 + 75, 28, 62}
e: Vec{1, 1, 1}.mult_s(0e-3)
c: Vec{1, .9, .8}.mult_s(.93)
refl: .refr
}, Sphere{
rad: 28
p: Vec{50 + 5, -28, 62}
e: Vec{1, 1, 1}.mult_s(1e+1)
c: Vec{1, 1, 1}.mult_s(0)
refl: .diff
}, Sphere{
rad: 300
p: Vec{50, 28, 62}
e: Vec{1, 1, 1}.mult_s(0e-3)
c: Vec{1, 1, 1}.mult_s(.93)
refl: .spec
}],
] // end of scene array
) )
/*********************************** Utilities *******************************/ //********************************** Utilities ******************************
[inline] [inline]
fn clamp(x f64) f64 { fn clamp(x f64) f64 {
if x < 0 { return 0 } if x < 0 {
if x > 1 { return 1 } return 0
}
if x > 1 {
return 1
}
return x return x
} }
[inline] [inline]
fn to_int(x f64) int { fn to_int(x f64) int {
p := math.pow(clamp(x), 1.0/2.2) p := math.pow(clamp(x), 1.0 / 2.2)
return int(p*255.0+0.5) return int(p * 255.0 + 0.5)
} }
fn intersect(r Ray, spheres &Sphere, nspheres int) (bool, f64, int){ fn intersect(r Ray, spheres &Sphere, nspheres int) (bool, f64, int) {
mut d := 0.0 mut d := 0.0
mut t := inf mut t := inf
mut id := 0 mut id := 0
for i:=nspheres-1; i >= 0; i-- { for i := nspheres - 1; i >= 0; i-- {
d = unsafe{spheres[i]}.intersect(r) d = unsafe { spheres[i] }.intersect(r)
if d > 0 && d < t { if d > 0 && d < t {
t = d t = d
id = i id = i
} }
} }
return (t < inf) , t, id return (t < inf), t, id
} }
// some casual random function, try to avoid the 0 // some casual random function, try to avoid the 0
fn rand_f64() f64 { fn rand_f64() f64 {
x := rand.u32() & 0x3FFF_FFFF x := rand.u32() & 0x3FFF_FFFF
return f64(x)/f64(0x3FFF_FFFF) return f64(x) / f64(0x3FFF_FFFF)
} }
const( const (
cache_len = 65536 // the 2*pi angle will be splitted in 65536 part cache_len = 65536 // the 2*pi angle will be splitted in 65536 part
cache_mask = cache_len - 1 // mask to speed-up the module process cache_mask = cache_len - 1 // mask to speed-up the module process
) )
struct Cache { struct Cache {
@ -254,7 +349,7 @@ mut:
fn new_tabs() Cache { fn new_tabs() Cache {
mut c := Cache{} mut c := Cache{}
inv_len := 1.0 / f64(cache_len) inv_len := 1.0 / f64(cache_len)
for i in 0..cache_len { for i in 0 .. cache_len {
x := f64(i) * math.pi * 2.0 * inv_len x := f64(i) * math.pi * 2.0 * inv_len
c.sin_tab[i] = math.sin(x) c.sin_tab[i] = math.sin(x)
c.cos_tab[i] = math.cos(x) c.cos_tab[i] = math.cos(x)
@ -262,31 +357,34 @@ fn new_tabs() Cache {
return c return c
} }
/************* Cache for sin/cos speed-up table and scene selector ***********/ //************ Cache for sin/cos speed-up table and scene selector **********
const ( const (
tabs = new_tabs() tabs = new_tabs()
) )
/******************* main function for the radiance calculation **************/ //****************** main function for the radiance calculation *************
fn radiance(r Ray, depthi int, scene_id int) Vec { fn radiance(r Ray, depthi int, scene_id int) Vec {
if depthi > 1024 { if depthi > 1024 {
eprintln('depthi: $depthi') eprintln('depthi: $depthi')
return Vec{} return Vec{}
} }
mut depth := depthi // actual depth in the reflection tree mut depth := depthi // actual depth in the reflection tree
mut t := 0.0 // distance to intersection mut t := 0.0 // distance to intersection
mut id := 0 // id of intersected object mut id := 0 // id of intersected object
mut res := false // result of intersect mut res := false // result of intersect
v_1 := 1.0 v_1 := 1.0
//v_2 := f64(2.0) // v_2 := f64(2.0)
scene := spheres[scene_id] scene := spheres[scene_id]
//res, t, id = intersect(r, id, tb.scene) // res, t, id = intersect(r, id, tb.scene)
res, t, id = intersect(r, scene.data, scene.len) res, t, id = intersect(r, scene.data, scene.len)
if !res { return Vec{} } //if miss, return black if !res {
return Vec{}
}
// if miss, return black
obj := scene[id] // the hit object obj := scene[id] // the hit object
x := r.o + r.d.mult_s(t) x := r.o + r.d.mult_s(t)
n := (x - obj.p).norm() n := (x - obj.p).norm()
@ -308,100 +406,95 @@ fn radiance(r Ray, depthi int, scene_id int) Vec {
depth++ depth++
if depth > 5 { if depth > 5 {
if rand_f64() < p { if rand_f64() < p {
f = f.mult_s(f64(1.0)/p) f = f.mult_s(f64(1.0) / p)
} else { } else {
return obj.e //R.R. return obj.e // R.R.
} }
} }
if obj.refl == .diff { // Ideal DIFFUSE reflection if obj.refl == .diff { // Ideal DIFFUSE reflection
// **Full Precision** // **Full Precision**
//r1 := f64(2.0 * math.pi) * rand_f64() // r1 := f64(2.0 * math.pi) * rand_f64()
// tabbed speed-up // tabbed speed-up
r1 := rand.u32() & cache_mask r1 := rand.u32() & cache_mask
r2 := rand_f64() r2 := rand_f64()
r2s := math.sqrt(r2) r2s := math.sqrt(r2)
w := nl w := nl
mut u := if math.abs(w.x) > f64(0.1) { mut u := if math.abs(w.x) > f64(0.1) { Vec{0, 1, 0} } else { Vec{1, 0, 0} }
Vec{0, 1, 0}
} else {
Vec{1, 0, 0}
}
u = u.cross(w).norm() u = u.cross(w).norm()
v := w.cross(u) v := w.cross(u)
// **Full Precision** // **Full Precision**
//d := (u.mult_s(math.cos(r1) * r2s) + v.mult_s(math.sin(r1) * r2s) + w.mult_s(1.0 - r2)).norm() // d := (u.mult_s(math.cos(r1) * r2s) + v.mult_s(math.sin(r1) * r2s) + w.mult_s(1.0 - r2)).norm()
// tabbed speed-up // tabbed speed-up
d := (u.mult_s(tabs.cos_tab[r1] * r2s) + v.mult_s(tabs.sin_tab[r1] * r2s) + w.mult_s(math.sqrt(f64(1.0) - r2))).norm() d := (u.mult_s(tabs.cos_tab[r1] * r2s) + v.mult_s(tabs.sin_tab[r1] * r2s) +
w.mult_s(math.sqrt(f64(1.0) - r2))).norm()
return obj.e + f * radiance(Ray{x, d}, depth, scene_id) return obj.e + f * radiance(Ray{x, d}, depth, scene_id)
} else { } else {
if obj.refl == .spec { // Ideal SPECULAR reflection if obj.refl == .spec { // Ideal SPECULAR reflection
return obj.e + f * radiance(Ray{x, r.d - n.mult_s(2.0 * n.dot(r.d)) }, depth, scene_id) return obj.e + f * radiance(Ray{x, r.d - n.mult_s(2.0 * n.dot(r.d))}, depth, scene_id)
} }
} }
refl_ray := Ray{x, r.d - n.mult_s(2.0 * n.dot(r.d))} // Ideal dielectric REFRACTION refl_ray := Ray{x, r.d - n.mult_s(2.0 * n.dot(r.d))} // Ideal dielectric REFRACTION
into := n.dot(nl) > 0 // Ray from outside going in? into := n.dot(nl) > 0 // Ray from outside going in?
nc := f64(1.0) nc := f64(1.0)
nt := f64(1.5) nt := f64(1.5)
nnt := if into { nc / nt } else { nt / nc } nnt := if into { nc / nt } else { nt / nc }
ddn := r.d.dot(nl) ddn := r.d.dot(nl)
cos2t := v_1 - nnt * nnt * (v_1 - ddn * ddn) cos2t := v_1 - nnt * nnt * (v_1 - ddn * ddn)
if cos2t < 0.0 { // Total internal reflection if cos2t < 0.0 { // Total internal reflection
return obj.e + f * radiance(refl_ray, depth, scene_id) return obj.e + f * radiance(refl_ray, depth, scene_id)
} }
dirc := if into { f64(1) } else { f64(-1) } dirc := if into { f64(1) } else { f64(-1) }
tdir := (r.d.mult_s(nnt) - n.mult_s(dirc * (ddn * nnt + math.sqrt(cos2t)))).norm() tdir := (r.d.mult_s(nnt) - n.mult_s(dirc * (ddn * nnt + math.sqrt(cos2t)))).norm()
a := nt - nc a := nt - nc
b := nt + nc b := nt + nc
r0 := a * a / (b * b) r0 := a * a / (b * b)
c := if into { v_1 + ddn } else { v_1 - tdir.dot(n) } c := if into { v_1 + ddn } else { v_1 - tdir.dot(n) }
re := r0 + (v_1 - r0) * c * c * c * c * c re := r0 + (v_1 - r0) * c * c * c * c * c
tr := v_1 - re tr := v_1 - re
pp := f64(.25) + f64(.5) * re pp := f64(.25) + f64(.5) * re
rp := re / pp rp := re / pp
tp := tr / (v_1 - pp) tp := tr / (v_1 - pp)
mut tmp := Vec{} mut tmp := Vec{}
if depth > 2 { if depth > 2 {
// Russian roulette // Russian roulette
tmp = if rand_f64() < pp { tmp = if rand_f64() < pp { radiance(refl_ray, depth, scene_id).mult_s(rp) } else { radiance(Ray{x, tdir},
radiance(refl_ray, depth, scene_id).mult_s(rp) depth, scene_id).mult_s(tp) }
} else {
radiance(Ray{x, tdir}, depth, scene_id).mult_s(tp)
}
} else { } else {
tmp = (radiance(refl_ray, depth, scene_id).mult_s(re)) + (radiance( Ray{x, tdir}, depth, scene_id).mult_s(tr)) tmp = (radiance(refl_ray, depth, scene_id).mult_s(re)) +
(radiance(Ray{x, tdir}, depth, scene_id).mult_s(tr))
} }
return obj.e + (f * tmp) return obj.e + (f * tmp)
} }
/************************ beam scan routine **********************************/ //*********************** beam scan routine *********************************
fn ray_trace(w int, h int, samps int, file_name string, scene_id int) Image { fn ray_trace(w int, h int, samps int, file_name string, scene_id int) Image {
image := new_image(w, h) image := new_image(w, h)
// inverse costants // inverse costants
w1 := f64(1.0 / f64(w)) w1 := f64(1.0 / f64(w))
h1 := f64(1.0 / f64(h)) h1 := f64(1.0 / f64(h))
samps1 := f64(1.0 / f64(samps)) samps1 := f64(1.0 / f64(samps))
cam := Ray{Vec{50, 52, 295.6}, Vec{0, -0.042612, -1}.norm()} // cam position, direction cam := Ray{Vec{50, 52, 295.6}, Vec{0, -0.042612, -1}.norm()} // cam position, direction
cx := Vec{ f64(w) * 0.5135 / f64(h), 0, 0} cx := Vec{f64(w) * 0.5135 / f64(h), 0, 0}
cy := cx.cross(cam.d).norm().mult_s(0.5135) cy := cx.cross(cam.d).norm().mult_s(0.5135)
mut r := Vec{} mut r := Vec{}
// speed-up constants // speed-up constants
@ -409,28 +502,28 @@ fn ray_trace(w int, h int, samps int, file_name string, scene_id int) Image {
v_2 := f64(2.0) v_2 := f64(2.0)
// OpenMP injection point! #pragma omp parallel for schedule(dynamic, 1) shared(c) // OpenMP injection point! #pragma omp parallel for schedule(dynamic, 1) shared(c)
for y:=0; y < h; y++ { for y := 0; y < h; y++ {
eprint("\rRendering (${samps * 4} spp) ${(100.0 * f64(y)) / (f64(h) - 1.0):5.2f}%") eprint('\rRendering (${samps * 4} spp) ${(100.0 * f64(y)) / (f64(h) - 1.0):5.2f}%')
for x in 0..w { for x in 0 .. w {
i := (h - y - 1) * w + x i := (h - y - 1) * w + x
mut ivec := unsafe{&image.data[i]} mut ivec := unsafe { &image.data[i] }
// we use sx and sy to perform a square subsampling of 4 samples // we use sx and sy to perform a square subsampling of 4 samples
for sy := 0; sy < 2; sy ++ { for sy := 0; sy < 2; sy++ {
for sx := 0; sx < 2; sx ++ { for sx := 0; sx < 2; sx++ {
r = Vec{0,0,0} r = Vec{0, 0, 0}
for _ in 0..samps { for _ in 0 .. samps {
r1 := v_2 * rand_f64() r1 := v_2 * rand_f64()
dx := if r1 < v_1 { math.sqrt(r1) - v_1 } else { v_1 - math.sqrt(v_2 - r1) } dx := if r1 < v_1 { math.sqrt(r1) - v_1 } else { v_1 - math.sqrt(v_2 - r1) }
r2 := v_2 * rand_f64() r2 := v_2 * rand_f64()
dy := if r2 < v_1 { math.sqrt(r2) - v_1 } else { v_1 - math.sqrt(v_2 - r2) } dy := if r2 < v_1 { math.sqrt(r2) - v_1 } else { v_1 - math.sqrt(v_2 - r2) }
d := cx.mult_s( ( (f64(sx) + 0.5 + dx)*0.5 + f64(x))*w1 - .5) + d := cx.mult_s(((f64(sx) + 0.5 + dx) * 0.5 + f64(x)) * w1 - .5) +
cy.mult_s( ( (f64(sy) + 0.5 + dy)*0.5 + f64(y))*h1 - .5) + cam.d cy.mult_s(((f64(sy) + 0.5 + dy) * 0.5 + f64(y)) * h1 - .5) + cam.d
r = r + radiance(Ray{cam.o+d.mult_s(140.0), d.norm()}, 0, scene_id).mult_s(samps1) r = r + radiance(Ray{cam.o +
d.mult_s(140.0), d.norm()}, 0, scene_id).mult_s(samps1)
} }
tmp_vec := Vec{clamp(r.x),clamp(r.y),clamp(r.z)}.mult_s(.25) tmp_vec := Vec{clamp(r.x), clamp(r.y), clamp(r.z)}.mult_s(.25)
(*ivec) = *ivec + tmp_vec (*ivec) = *ivec + tmp_vec
} }
} }
@ -446,7 +539,7 @@ fn main() {
} }
mut width := 320 // width of the rendering in pixels mut width := 320 // width of the rendering in pixels
mut height := 200 // height of the rendering in pixels mut height := 200 // height of the rendering in pixels
mut samples := 4 // number of samples per pixel, increase for better quality mut samples := 4 // number of samples per pixel, increase for better quality
mut scene_id := 0 // scene to render [0 cornell box,1 sunset,2 psyco] mut scene_id := 0 // scene to render [0 cornell box,1 sunset,2 psyco]
mut file_name := 'image.ppm' // name of the output file in .ppm format mut file_name := 'image.ppm' // name of the output file in .ppm format
@ -465,20 +558,18 @@ fn main() {
if os.args.len == 6 { if os.args.len == 6 {
height = os.args[5].int() height = os.args[5].int()
} }
// change the seed for a different result // change the seed for a different result
rand.seed([u32(2020), 0]) rand.seed([u32(2020), 0])
t1:=time.ticks() t1 := time.ticks()
image := ray_trace(width, height, samples, file_name, scene_id) image := ray_trace(width, height, samples, file_name, scene_id)
t2:=time.ticks() t2 := time.ticks()
eprintln('\nRendering finished. Took: ${(t2 - t1):5}ms')
eprintln('\nRendering finished. Took: ${(t2-t1):5}ms') image.save_as_ppm(file_name)
t3 := time.ticks()
image.save_as_ppm( file_name ) eprintln('Image saved as [$file_name]. Took: ${(t3 - t2):5}ms')
t3:=time.ticks()
eprintln('Image saved as [${file_name}]. Took: ${(t3-t2):5}ms')
} }

View File

@ -2,12 +2,12 @@ import term.ui as tui
const ( const (
colors = [ colors = [
tui.Color{33, 150, 243} tui.Color{33, 150, 243},
tui.Color{0, 150, 136} tui.Color{0, 150, 136},
tui.Color{205, 220, 57} tui.Color{205, 220, 57},
tui.Color{255, 152, 0} tui.Color{255, 152, 0},
tui.Color{244, 67, 54} tui.Color{244, 67, 54},
tui.Color{156, 39, 176} tui.Color{156, 39, 176},
] ]
) )
@ -66,27 +66,33 @@ fn event(e &tui.Event, x voidptr) {
} }
.space, .enter { .space, .enter {
app.color_idx++ app.color_idx++
if app.color_idx == colors.len { app.color_idx = 0 } if app.color_idx == colors.len {
app.color_idx = 0
}
app.color = colors[app.color_idx] app.color = colors[app.color_idx]
} else {} }
else {}
} }
} .mouse_move, .mouse_drag, .mouse_down { }
app.points << Point{ e.x, e.y } .mouse_move, .mouse_drag, .mouse_down {
} .mouse_scroll { app.points << Point{e.x, e.y}
}
.mouse_scroll {
d := if e.direction == .up { 0.1 } else { -0.1 } d := if e.direction == .up { 0.1 } else { -0.1 }
app.cut_rate += d app.cut_rate += d
if app.cut_rate < 1 { app.cut_rate = 1 } if app.cut_rate < 1 {
} else {} app.cut_rate = 1
}
}
else {}
} }
} }
mut app := &App{} mut app := &App{}
app.tui = tui.init( app.tui = tui.init(
user_data: app, user_data: app
frame_fn: frame, frame_fn: frame
event_fn: event, event_fn: event
hide_cursor: true hide_cursor: true
) )
app.tui.run() ?
app.tui.run()

View File

@ -11,29 +11,35 @@ fn event(e &tui.Event, x voidptr) {
app.tui.set_cursor_position(0, 0) app.tui.set_cursor_position(0, 0)
app.tui.write('V term.input event viewer (press `esc` to exit)\n\n') app.tui.write('V term.input event viewer (press `esc` to exit)\n\n')
app.tui.write('$e') app.tui.write('$e')
app.tui.write('\n\nRaw event bytes: "${e.utf8.bytes().hex()}" = ${e.utf8.bytes()}') app.tui.write('\n\nRaw event bytes: "$e.utf8.bytes().hex()" = $e.utf8.bytes()')
if e.modifiers != 0 { if e.modifiers != 0 {
app.tui.write('\nModifiers: $e.modifiers = ') app.tui.write('\nModifiers: $e.modifiers = ')
if e.modifiers & tui.ctrl != 0 { app.tui.write('ctrl. ') } if e.modifiers & tui.ctrl != 0 {
if e.modifiers & tui.shift != 0 { app.tui.write('shift ') } app.tui.write('ctrl. ')
if e.modifiers & tui.alt != 0 { app.tui.write('alt. ') } }
if e.modifiers & tui.shift != 0 {
app.tui.write('shift ')
}
if e.modifiers & tui.alt != 0 {
app.tui.write('alt. ')
}
} }
app.tui.flush() app.tui.flush()
if e.typ == .key_down && e.code == .escape { exit(0) } if e.typ == .key_down && e.code == .escape {
exit(0)
}
} }
mut app := &App{} mut app := &App{}
app.tui = tui.init( app.tui = tui.init(
user_data: app, user_data: app
event_fn: event event_fn: event
window_title: 'V term.ui event viewer' window_title: 'V term.ui event viewer'
hide_cursor: true hide_cursor: true
capture_events: true capture_events: true
frame_rate: 60 frame_rate: 60
use_alternate_buffer: false use_alternate_buffer: false
) )
println('V term.ui event viewer (press `esc` to exit)\n\n') println('V term.ui event viewer (press `esc` to exit)\n\n')
app.tui.run() app.tui.run() ?

View File

@ -19,7 +19,7 @@ const (
struct App { struct App {
mut: mut:
tui &ui.Context = 0 tui &ui.Context = 0
mode Mode = Mode.menu mode Mode = Mode.menu
width int width int
height int height int
game &Game = 0 game &Game = 0
@ -35,10 +35,10 @@ fn (mut a App) init() {
a.width = w a.width = w
a.height = h a.height = h
term.erase_del_clear() term.erase_del_clear()
term.set_cursor_position({ term.set_cursor_position(
x: 0 x: 0
y: 0 y: 0
}) )
} }
fn (mut a App) start_game() { fn (mut a App) start_game() {
@ -66,10 +66,10 @@ fn (mut a App) quit() {
a.game.quit() a.game.quit()
return return
} }
term.set_cursor_position({ term.set_cursor_position(
x: 0 x: 0
y: 0 y: 0
}) )
exit(0) exit(0)
} }
@ -482,7 +482,7 @@ fn event(e &ui.Event, x voidptr) {
// main // main
mut app := &App{} mut app := &App{}
app.tui = ui.init({ app.tui = ui.init(
user_data: app user_data: app
init_fn: init init_fn: init
frame_fn: frame frame_fn: frame
@ -492,5 +492,5 @@ app.tui = ui.init({
capture_events: true capture_events: true
hide_cursor: true hide_cursor: true
frame_rate: 60 frame_rate: 60
}) )
app.tui.run() app.tui.run() ?

View File

@ -34,8 +34,8 @@ fn event(e &tui.Event, x voidptr) {
app.is_drag = true app.is_drag = true
app.cur_rect = { app.cur_rect = {
c: random_color() c: random_color()
x: e.x x: e.x
y: e.y y: e.y
x2: e.x x2: e.x
y2: e.y y2: e.y
} }
@ -43,20 +43,28 @@ fn event(e &tui.Event, x voidptr) {
.mouse_drag { .mouse_drag {
app.cur_rect.x2 = e.x app.cur_rect.x2 = e.x
app.cur_rect.y2 = e.y app.cur_rect.y2 = e.y
} .mouse_up { }
.mouse_up {
app.rects << app.cur_rect app.rects << app.cur_rect
app.is_drag = false app.is_drag = false
} .key_down { }
if e.code == .c { app.rects.clear() } .key_down {
else if e.code == .escape { exit(0) } if e.code == .c {
} else {} app.rects.clear()
} else if e.code == .escape {
exit(0)
}
}
else {}
} }
app.redraw = true app.redraw = true
} }
fn frame(x voidptr) { fn frame(x voidptr) {
mut app := &App(x) mut app := &App(x)
if !app.redraw { return } if !app.redraw {
return
}
app.tui.clear() app.tui.clear()
@ -76,15 +84,12 @@ fn frame(x voidptr) {
app.redraw = false app.redraw = false
} }
mut app := &App{} mut app := &App{}
app.tui = tui.init( app.tui = tui.init(
user_data: app, user_data: app
event_fn: event, event_fn: event
frame_fn: frame frame_fn: frame
hide_cursor: true hide_cursor: true
frame_rate: 60 frame_rate: 60
) )
app.tui.run() ?
app.tui.run()

View File

@ -3,73 +3,73 @@
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module main module main
import term.ui as tui import term.ui
// The color palette, taken from Google's Material design // The color palette, taken from Google's Material design
const ( const (
colors = [ colors = [
[ [
tui.Color{239, 154, 154}, ui.Color{239, 154, 154},
tui.Color{244, 143, 177}, ui.Color{244, 143, 177},
tui.Color{206, 147, 216}, ui.Color{206, 147, 216},
tui.Color{179, 157, 219}, ui.Color{179, 157, 219},
tui.Color{159, 168, 218}, ui.Color{159, 168, 218},
tui.Color{144, 202, 249}, ui.Color{144, 202, 249},
tui.Color{129, 212, 250}, ui.Color{129, 212, 250},
tui.Color{128, 222, 234}, ui.Color{128, 222, 234},
tui.Color{128, 203, 196}, ui.Color{128, 203, 196},
tui.Color{165, 214, 167}, ui.Color{165, 214, 167},
tui.Color{197, 225, 165}, ui.Color{197, 225, 165},
tui.Color{230, 238, 156}, ui.Color{230, 238, 156},
tui.Color{255, 245, 157}, ui.Color{255, 245, 157},
tui.Color{255, 224, 130}, ui.Color{255, 224, 130},
tui.Color{255, 204, 128}, ui.Color{255, 204, 128},
tui.Color{255, 171, 145}, ui.Color{255, 171, 145},
tui.Color{188, 170, 164}, ui.Color{188, 170, 164},
tui.Color{238, 238, 238}, ui.Color{238, 238, 238},
tui.Color{176, 190, 197}, ui.Color{176, 190, 197},
], ],
[ [
tui.Color{244, 67, 54}, ui.Color{244, 67, 54},
tui.Color{233, 30, 99}, ui.Color{233, 30, 99},
tui.Color{156, 39, 176}, ui.Color{156, 39, 176},
tui.Color{103, 58, 183}, ui.Color{103, 58, 183},
tui.Color{63, 81, 181}, ui.Color{63, 81, 181},
tui.Color{33, 150, 243}, ui.Color{33, 150, 243},
tui.Color{3, 169, 244}, ui.Color{3, 169, 244},
tui.Color{0, 188, 212}, ui.Color{0, 188, 212},
tui.Color{0, 150, 136}, ui.Color{0, 150, 136},
tui.Color{76, 175, 80}, ui.Color{76, 175, 80},
tui.Color{139, 195, 74}, ui.Color{139, 195, 74},
tui.Color{205, 220, 57}, ui.Color{205, 220, 57},
tui.Color{255, 235, 59}, ui.Color{255, 235, 59},
tui.Color{255, 193, 7}, ui.Color{255, 193, 7},
tui.Color{255, 152, 0}, ui.Color{255, 152, 0},
tui.Color{255, 87, 34}, ui.Color{255, 87, 34},
tui.Color{121, 85, 72}, ui.Color{121, 85, 72},
tui.Color{120, 120, 120}, ui.Color{120, 120, 120},
tui.Color{96, 125, 139}, ui.Color{96, 125, 139},
], ],
[ [
tui.Color{198, 40, 40}, ui.Color{198, 40, 40},
tui.Color{173, 20, 87}, ui.Color{173, 20, 87},
tui.Color{106, 27, 154}, ui.Color{106, 27, 154},
tui.Color{69, 39, 160}, ui.Color{69, 39, 160},
tui.Color{40, 53, 147}, ui.Color{40, 53, 147},
tui.Color{21, 101, 192}, ui.Color{21, 101, 192},
tui.Color{2, 119, 189}, ui.Color{2, 119, 189},
tui.Color{0, 131, 143}, ui.Color{0, 131, 143},
tui.Color{0, 105, 92}, ui.Color{0, 105, 92},
tui.Color{46, 125, 50}, ui.Color{46, 125, 50},
tui.Color{85, 139, 47}, ui.Color{85, 139, 47},
tui.Color{158, 157, 36}, ui.Color{158, 157, 36},
tui.Color{249, 168, 37}, ui.Color{249, 168, 37},
tui.Color{255, 143, 0}, ui.Color{255, 143, 0},
tui.Color{239, 108, 0}, ui.Color{239, 108, 0},
tui.Color{216, 67, 21}, ui.Color{216, 67, 21},
tui.Color{78, 52, 46}, ui.Color{78, 52, 46},
tui.Color{33, 33, 33}, ui.Color{33, 33, 33},
tui.Color{55, 71, 79}, ui.Color{55, 71, 79},
], ],
] ]
) )
@ -90,18 +90,18 @@ const (
struct App { struct App {
mut: mut:
tui &tui.Context = 0 ui &ui.Context = 0
header_text []string header_text []string
mouse_pos Point mouse_pos Point
msg string msg string
msg_hide_tick int msg_hide_tick int
primary_color tui.Color = colors[1][6] primary_color ui.Color = colors[1][6]
secondary_color tui.Color = colors[1][9] secondary_color ui.Color = colors[1][9]
primary_color_idx int = 25 primary_color_idx int = 25
secondary_color_idx int = 28 secondary_color_idx int = 28
bg_color tui.Color = tui.Color{0, 0, 0} bg_color ui.Color = ui.Color{0, 0, 0}
drawing [][]tui.Color = [][]tui.Color{len: h, init: []tui.Color{len: w}} drawing [][]ui.Color = [][]ui.Color{len: h, init: []ui.Color{len: w}}
size int = 1 size int = 1
should_redraw bool = true should_redraw bool = true
is_dragging bool is_dragging bool
} }
@ -114,24 +114,24 @@ mut:
fn main() { fn main() {
mut app := &App{} mut app := &App{}
app.tui = tui.init({ app.ui = ui.init(
user_data: app user_data: app
frame_fn: frame frame_fn: frame
event_fn: event event_fn: event
frame_rate: frame_rate frame_rate: frame_rate
hide_cursor: true hide_cursor: true
window_title: 'V terminal pixelart drawing app' window_title: 'V terminal pixelart drawing app'
}) )
app.mouse_pos.x = 40 app.mouse_pos.x = 40
app.mouse_pos.y = 15 app.mouse_pos.y = 15
app.tui.clear() app.ui.clear()
app.tui.run() app.ui.run() ?
} }
fn frame(x voidptr) { fn frame(x voidptr) {
mut app := &App(x) mut app := &App(x)
mut redraw := app.should_redraw mut redraw := app.should_redraw
if app.msg != '' && app.tui.frame_count >= app.msg_hide_tick { if app.msg != '' && app.ui.frame_count >= app.msg_hide_tick {
app.msg = '' app.msg = ''
redraw = true redraw = true
} }
@ -141,12 +141,12 @@ fn frame(x voidptr) {
} }
} }
fn event(event &tui.Event, x voidptr) { fn event(event &ui.Event, x voidptr) {
mut app := &App(x) mut app := &App(x)
match event.typ { match event.typ {
.mouse_down { .mouse_down {
app.is_dragging = true app.is_dragging = true
if app.tui.window_height - event.y < 5 { if app.ui.window_height - event.y < 5 {
app.footer_click(event) app.footer_click(event)
} else { } else {
app.paint(event) app.paint(event)
@ -174,8 +174,8 @@ fn event(event &tui.Event, x voidptr) {
y: event.y y: event.y
} }
d := event.direction == .down d := event.direction == .down
if event.modifiers & tui.ctrl != 0 { if event.modifiers & ui.ctrl != 0 {
p := event.modifiers & tui.shift == 0 p := event.modifiers & ui.shift == 0
c := if d { c := if d {
if p { app.primary_color_idx - 1 } else { app.secondary_color_idx - 1 } if p { app.primary_color_idx - 1 } else { app.secondary_color_idx - 1 }
} else { } else {
@ -183,53 +183,72 @@ fn event(event &tui.Event, x voidptr) {
} }
app.select_color(p, c) app.select_color(p, c)
} else { } else {
if d { app.inc_size() } else { app.dec_size() } if d {
app.inc_size()
} else {
app.dec_size()
}
} }
} }
.key_down { .key_down {
match event.code { match event.code {
.f1, ._1 { .f1, ._1 {
oevent := *event oevent := *event
nevent := tui.Event{ ...oevent, button: tui.MouseButton.left, x: app.mouse_pos.x , y: app.mouse_pos.y } nevent := ui.Event{
...oevent
button: ui.MouseButton.left
x: app.mouse_pos.x
y: app.mouse_pos.y
}
app.paint(nevent) app.paint(nevent)
} }
.f2, ._2 { .f2, ._2 {
oevent := *event oevent := *event
nevent := tui.Event{ ...oevent, button: tui.MouseButton.right, x: app.mouse_pos.x , y: app.mouse_pos.y } nevent := ui.Event{
...oevent
button: ui.MouseButton.right
x: app.mouse_pos.x
y: app.mouse_pos.y
}
app.paint(nevent) app.paint(nevent)
} }
.space { .space {
oevent := *event oevent := *event
nevent := tui.Event{ ...oevent, button: tui.MouseButton.middle, x: app.mouse_pos.x , y: app.mouse_pos.y } nevent := ui.Event{
...oevent
button: ui.MouseButton.middle
x: app.mouse_pos.x
y: app.mouse_pos.y
}
app.paint(nevent) app.paint(nevent)
} }
.j, .down { .j, .down {
if event.modifiers & tui.shift != 0 { if event.modifiers & ui.shift != 0 {
app.set_pixel((1 + app.mouse_pos.x) / 2, app.mouse_pos.y, app.primary_color) app.set_pixel((1 + app.mouse_pos.x) / 2, app.mouse_pos.y, app.primary_color)
} }
app.mouse_pos.y++ app.mouse_pos.y++
} }
.k, .up { .k, .up {
if event.modifiers & tui.shift != 0 { if event.modifiers & ui.shift != 0 {
app.set_pixel((1 + app.mouse_pos.x) / 2, app.mouse_pos.y, app.primary_color) app.set_pixel((1 + app.mouse_pos.x) / 2, app.mouse_pos.y, app.primary_color)
} }
app.mouse_pos.y-- app.mouse_pos.y--
} }
.h, .left { .h, .left {
if event.modifiers & tui.shift != 0 { if event.modifiers & ui.shift != 0 {
app.set_pixel((1 + app.mouse_pos.x) / 2, app.mouse_pos.y, app.primary_color) app.set_pixel((1 + app.mouse_pos.x) / 2, app.mouse_pos.y, app.primary_color)
} }
app.mouse_pos.x -= 2 app.mouse_pos.x -= 2
} }
.l, .right { .l, .right {
if event.modifiers & tui.shift != 0 { if event.modifiers & ui.shift != 0 {
app.set_pixel((1 + app.mouse_pos.x) / 2, app.mouse_pos.y, app.primary_color) app.set_pixel((1 + app.mouse_pos.x) / 2, app.mouse_pos.y, app.primary_color)
} }
app.mouse_pos.x += 2 app.mouse_pos.x += 2
} }
.t { .t {
p := event.modifiers & tui.alt == 0 p := event.modifiers & ui.alt == 0
c := if event.modifiers & tui.shift != 0 { c := if event.modifiers & ui.shift != 0 {
if p { app.primary_color_idx - 19 } else { app.secondary_color_idx - 19 } if p { app.primary_color_idx - 19 } else { app.secondary_color_idx - 19 }
} else { } else {
if p { app.primary_color_idx + 19 } else { app.secondary_color_idx + 19 } if p { app.primary_color_idx + 19 } else { app.secondary_color_idx + 19 }
@ -237,8 +256,8 @@ fn event(event &tui.Event, x voidptr) {
app.select_color(p, c) app.select_color(p, c)
} }
.r { .r {
p := event.modifiers & tui.alt == 0 p := event.modifiers & ui.alt == 0
c := if event.modifiers & tui.shift != 0 { c := if event.modifiers & ui.shift != 0 {
if p { app.primary_color_idx - 1 } else { app.secondary_color_idx - 1 } if p { app.primary_color_idx - 1 } else { app.secondary_color_idx - 1 }
} else { } else {
if p { app.primary_color_idx + 1 } else { app.secondary_color_idx + 1 } if p { app.primary_color_idx + 1 } else { app.secondary_color_idx + 1 }
@ -252,7 +271,7 @@ fn event(event &tui.Event, x voidptr) {
app.dec_size() app.dec_size()
} }
.c { .c {
app.drawing = [][]tui.Color{len: h, init: []tui.Color{len: w}} app.drawing = [][]ui.Color{len: h, init: []ui.Color{len: w}}
} }
.q, .escape { .q, .escape {
app.render(true) app.render(true)
@ -267,14 +286,14 @@ fn event(event &tui.Event, x voidptr) {
} }
fn (mut app App) render(paint_only bool) { fn (mut app App) render(paint_only bool) {
app.tui.clear() app.ui.clear()
app.draw_header() app.draw_header()
app.draw_content() app.draw_content()
if !paint_only { if !paint_only {
app.draw_footer() app.draw_footer()
app.draw_cursor() app.draw_cursor()
} }
app.tui.flush() app.ui.flush()
} }
fn (mut app App) select_color(primary bool, idx int) { fn (mut app App) select_color(primary bool, idx int) {
@ -293,10 +312,10 @@ fn (mut app App) select_color(primary bool, idx int) {
app.show_msg('set $c_str color idx: $idx', 1) app.show_msg('set $c_str color idx: $idx', 1)
} }
fn (mut app App) set_pixel(x_ int, y_ int, c tui.Color) { fn (mut app App) set_pixel(x_ int, y_ int, c ui.Color) {
// Term coords start at 1, and adjust for the header // Term coords start at 1, and adjust for the header
x, y := x_ - 1, y_ - 4 x, y := x_ - 1, y_ - 4
if y < 0 || app.tui.window_height - y < 3 { if y < 0 || app.ui.window_height - y < 3 {
return return
} }
if y >= app.drawing.len || x < 0 || x >= app.drawing[0].len { if y >= app.drawing.len || x < 0 || x >= app.drawing[0].len {
@ -305,8 +324,8 @@ fn (mut app App) set_pixel(x_ int, y_ int, c tui.Color) {
app.drawing[y][x] = c app.drawing[y][x] = c
} }
fn (mut app App) paint(event &tui.Event) { fn (mut app App) paint(event &ui.Event) {
if event.y < 4 || app.tui.window_height - event.y < 4 { if event.y < 4 || app.ui.window_height - event.y < 4 {
return return
} }
x_start, y_start := int(f32((event.x - 1) / 2) - app.size / 2 + 1), event.y - app.size / 2 x_start, y_start := int(f32((event.x - 1) / 2) - app.size / 2 + 1), event.y - app.size / 2
@ -323,38 +342,38 @@ fn (mut app App) paint(event &tui.Event) {
} }
fn (mut app App) draw_content() { fn (mut app App) draw_content() {
w_, mut h_ := app.tui.window_width / 2, app.tui.window_height - 8 w_, mut h_ := app.ui.window_width / 2, app.ui.window_height - 8
if h_ > app.drawing.len { if h_ > app.drawing.len {
h_ = app.drawing.len h_ = app.drawing.len
} }
for row_idx, row in app.drawing[..h_] { for row_idx, row in app.drawing[..h_] {
app.tui.set_cursor_position(0, row_idx + 4) app.ui.set_cursor_position(0, row_idx + 4)
mut last := tui.Color{0, 0, 0} mut last := ui.Color{0, 0, 0}
for cell in row[..w_] { for cell in row[..w_] {
if cell.r == 0 && cell.g == 0 && cell.b == 0 { if cell.r == 0 && cell.g == 0 && cell.b == 0 {
if !(cell.r == last.r && cell.g == last.g && cell.b == last.b) { if !(cell.r == last.r && cell.g == last.g && cell.b == last.b) {
app.tui.reset() app.ui.reset()
} }
} else { } else {
if !(cell.r == last.r && cell.g == last.g && cell.b == last.b) { if !(cell.r == last.r && cell.g == last.g && cell.b == last.b) {
app.tui.set_bg_color(cell) app.ui.set_bg_color(cell)
} }
} }
app.tui.write(spaces) app.ui.write(spaces)
last = cell last = cell
} }
app.tui.reset() app.ui.reset()
} }
} }
fn (mut app App) draw_cursor() { fn (mut app App) draw_cursor() {
if app.mouse_pos.y in [3, app.tui.window_height - 5] { if app.mouse_pos.y in [3, app.ui.window_height - 5] {
// inside the horizontal separators // inside the horizontal separators
return return
} }
cursor_color := if app.is_dragging { tui.Color{220, 220, 220} } else { tui.Color{160, 160, 160} } cursor_color := if app.is_dragging { ui.Color{220, 220, 220} } else { ui.Color{160, 160, 160} }
app.tui.set_bg_color(cursor_color) app.ui.set_bg_color(cursor_color)
if app.mouse_pos.y >= 3 && app.mouse_pos.y <= app.tui.window_height - 4 { if app.mouse_pos.y >= 3 && app.mouse_pos.y <= app.ui.window_height - 4 {
// inside the main content // inside the main content
mut x_start := int(f32((app.mouse_pos.x - 1) / 2) - app.size / 2 + 1) * 2 - 1 mut x_start := int(f32((app.mouse_pos.x - 1) / 2) - app.size / 2 + 1) * 2 - 1
mut y_start := app.mouse_pos.y - app.size / 2 mut y_start := app.mouse_pos.y - app.size / 2
@ -366,70 +385,71 @@ fn (mut app App) draw_cursor() {
if y_start < 4 { if y_start < 4 {
y_start = 4 y_start = 4
} }
if x_end > app.tui.window_width { if x_end > app.ui.window_width {
x_end = app.tui.window_width x_end = app.ui.window_width
} }
if y_end > app.tui.window_height - 5 { if y_end > app.ui.window_height - 5 {
y_end = app.tui.window_height - 5 y_end = app.ui.window_height - 5
} }
app.tui.draw_rect(x_start, y_start, x_end, y_end) app.ui.draw_rect(x_start, y_start, x_end, y_end)
} else { } else {
app.tui.draw_text(app.mouse_pos.x, app.mouse_pos.y, space) app.ui.draw_text(app.mouse_pos.x, app.mouse_pos.y, space)
} }
app.tui.reset() app.ui.reset()
} }
fn (mut app App) draw_header() { fn (mut app App) draw_header() {
if app.msg != '' { if app.msg != '' {
app.tui.set_color({ app.ui.set_color(
r: 0 r: 0
g: 0 g: 0
b: 0 b: 0
}) )
app.tui.set_bg_color({ app.ui.set_bg_color(
r: 220 r: 220
g: 220 g: 220
b: 220 b: 220
}) )
app.tui.draw_text(0, 0, ' $app.msg ') app.ui.draw_text(0, 0, ' $app.msg ')
app.tui.reset() app.ui.reset()
} }
app.tui.draw_text(3, 2, /* 'tick: $app.tui.frame_count | ' + */ 'terminal size: ($app.tui.window_width, $app.tui.window_height) | primary color: $app.primary_color.hex() | secondary color: $app.secondary_color.hex()') //'tick: $app.ui.frame_count | ' +
app.tui.horizontal_separator(3) app.ui.draw_text(3, 2, 'terminal size: ($app.ui.window_width, $app.ui.window_height) | primary color: $app.primary_color.hex() | secondary color: $app.secondary_color.hex()')
app.ui.horizontal_separator(3)
} }
fn (mut app App) draw_footer() { fn (mut app App) draw_footer() {
_, wh := app.tui.window_width, app.tui.window_height _, wh := app.ui.window_width, app.ui.window_height
app.tui.horizontal_separator(wh - 4) app.ui.horizontal_separator(wh - 4)
for i, color_row in colors { for i, color_row in colors {
for j, color in color_row { for j, color in color_row {
x := j * 3 + 19 x := j * 3 + 19
y := wh - 3 + i y := wh - 3 + i
app.tui.set_bg_color(color) app.ui.set_bg_color(color)
if app.primary_color_idx == j + (i * 19) { if app.primary_color_idx == j + (i * 19) {
app.tui.set_color(r: 0, g: 0, b: 0) app.ui.set_color(r: 0, g: 0, b: 0)
app.tui.draw_text(x, y, '><') app.ui.draw_text(x, y, '><')
app.tui.reset_color() app.ui.reset_color()
} else if app.secondary_color_idx == j + (i * 19) { } else if app.secondary_color_idx == j + (i * 19) {
app.tui.set_color(r: 255, g: 255, b: 255) app.ui.set_color(r: 255, g: 255, b: 255)
app.tui.draw_text(x, y, '><') app.ui.draw_text(x, y, '><')
app.tui.reset_color() app.ui.reset_color()
} else { } else {
app.tui.draw_rect(x, y, x + 1, y) app.ui.draw_rect(x, y, x + 1, y)
} }
} }
} }
app.tui.reset_bg_color() app.ui.reset_bg_color()
app.tui.draw_text(3, wh - 3, select_color) app.ui.draw_text(3, wh - 3, select_color)
app.tui.bold() app.ui.bold()
app.tui.draw_text(3, wh - 1, '$select_size $app.size') app.ui.draw_text(3, wh - 1, '$select_size $app.size')
app.tui.reset() app.ui.reset()
// TODO: help button // TODO: help button
// if ww >= 90 { // if ww >= 90 {
// app.tui.draw_text(80, wh - 3, help_1) // app.ui.draw_text(80, wh - 3, help_1)
// app.tui.draw_text(80, wh - 2, help_2) // app.ui.draw_text(80, wh - 2, help_2)
// app.tui.draw_text(80, wh - 1, help_3) // app.ui.draw_text(80, wh - 1, help_3)
// } // }
} }
@ -449,8 +469,8 @@ fn (mut app App) dec_size() {
app.show_msg('dec. size: $app.size', 1) app.show_msg('dec. size: $app.size', 1)
} }
fn (mut app App) footer_click(event &tui.Event) { fn (mut app App) footer_click(event &ui.Event) {
footer_y := 3 - (app.tui.window_height - event.y) footer_y := 3 - (app.ui.window_height - event.y)
match event.x { match event.x {
8...11 { 8...11 {
app.inc_size() app.inc_size()
@ -464,7 +484,9 @@ fn (mut app App) footer_click(event &tui.Event) {
return return
} }
idx := footer_y * 19 - 6 + event.x / 3 idx := footer_y * 19 - 6 + event.x / 3
if idx < 0 || idx > 56 { return } if idx < 0 || idx > 56 {
return
}
app.select_color(event.button == .left, idx) app.select_color(event.button == .left, idx)
} }
else {} else {}
@ -473,6 +495,6 @@ fn (mut app App) footer_click(event &tui.Event) {
fn (mut app App) show_msg(text string, time int) { fn (mut app App) show_msg(text string, time int) {
frames := time * frame_rate frames := time * frame_rate
app.msg_hide_tick = if time > 0 { int(app.tui.frame_count) + frames } else { -1 } app.msg_hide_tick = if time > 0 { int(app.ui.frame_count) + frames } else { -1 }
app.msg = text app.msg = text
} }

View File

@ -26,7 +26,7 @@ pub:
struct App { struct App {
mut: mut:
tui &tui.Context = 0 tui &tui.Context = 0
ed &Buffer = 0 ed &Buffer = 0
current_file int current_file int
files []string files []string
status string status string
@ -44,7 +44,7 @@ fn (mut a App) set_status(msg string, duration_ms int) {
fn (mut a App) save() { fn (mut a App) save() {
if a.cfile().len > 0 { if a.cfile().len > 0 {
b := a.ed b := a.ed
os.write_file(a.cfile(), b.raw()) os.write_file(a.cfile(), b.raw()) or { panic(err) }
a.set_status('Saved', 2000) a.set_status('Saved', 2000)
} else { } else {
a.set_status('No file loaded', 4000) a.set_status('No file loaded', 4000)
@ -79,7 +79,6 @@ fn (mut a App) visit_next_file() {
a.init_file() a.init_file()
} }
fn (mut a App) footer() { fn (mut a App) footer() {
w, h := a.tui.window_width, a.tui.window_height w, h := a.tui.window_width, a.tui.window_height
mut b := a.ed mut b := a.ed
@ -99,16 +98,16 @@ fn (mut a App) footer() {
if a.t <= 0 { if a.t <= 0 {
status = '' status = ''
} else { } else {
a.tui.set_bg_color({ a.tui.set_bg_color(
r: 200 r: 200
g: 200 g: 200
b: 200 b: 200
}) )
a.tui.set_color({ a.tui.set_color(
r: 0 r: 0
g: 0 g: 0
b: 0 b: 0
}) )
a.tui.draw_text((w + 4 - status.len) / 2, h - 1, ' $status ') a.tui.draw_text((w + 4 - status.len) / 2, h - 1, ' $status ')
a.tui.reset() a.tui.reset()
a.t -= 33 a.t -= 33
@ -118,8 +117,8 @@ fn (mut a App) footer() {
struct Buffer { struct Buffer {
tab_width int = 4 tab_width int = 4
pub mut: pub mut:
lines []string lines []string
cursor Cursor cursor Cursor
} }
fn (b Buffer) flat() string { fn (b Buffer) flat() string {
@ -303,7 +302,7 @@ fn (mut b Buffer) free() {
for line in b.lines { for line in b.lines {
line.free() line.free()
} }
unsafe {b.lines.free()} unsafe { b.lines.free() }
} }
fn (mut b Buffer) move_updown(amount int) { fn (mut b Buffer) move_updown(amount int) {
@ -334,7 +333,7 @@ fn (mut b Buffer) move_cursor(amount int, movement Movement) {
b.move_updown(-dlines) b.move_updown(-dlines)
} }
.page_down { .page_down {
dlines := imin(b.lines.len-1, b.cursor.pos_y + amount) - b.cursor.pos_y dlines := imin(b.lines.len - 1, b.cursor.pos_y + amount) - b.cursor.pos_y
b.move_updown(dlines) b.move_updown(dlines)
} }
.left { .left {
@ -374,13 +373,19 @@ fn (mut b Buffer) move_to_word(movement Movement) {
x = 0 x = 0
} }
// first, move past all non-`a-zA-Z0-9_` characters // first, move past all non-`a-zA-Z0-9_` characters
for x+a >= 0 && x+a < line.len && !(line[x+a].is_letter() || line[x+a].is_digit() || line[x+a] == `_`) { x += a } for x + a >= 0 && x + a < line.len && !(line[x + a].is_letter()
|| line[x + a].is_digit()|| line[x + a] == `_`) {
x += a
}
// then, move past all the letters and numbers // then, move past all the letters and numbers
for x+a >= 0 && x+a < line.len && (line[x+a].is_letter() || line[x+a].is_digit() || line[x+a] == `_`) { x += a } for x + a >= 0 && x + a < line.len && (line[x + a].is_letter()
|| line[x + a].is_digit()|| line[x + a] == `_`) {
x += a
}
// if the cursor is out of bounds, move it to the next/previous line // if the cursor is out of bounds, move it to the next/previous line
if x + a >= 0 && x + a <= line.len { if x + a >= 0 && x + a <= line.len {
x += a x += a
} else if a < 0 && y+1 > b.lines.len && y-1 >= 0 { } else if a < 0 && y + 1 > b.lines.len && y - 1 >= 0 {
y += a y += a
x = 0 x = 0
} }
@ -388,11 +393,19 @@ fn (mut b Buffer) move_to_word(movement Movement) {
} }
fn imax(x int, y int) int { fn imax(x int, y int) int {
return if x < y { y } else { x } return if x < y {
y
} else {
x
}
} }
fn imin(x int, y int) int { fn imin(x int, y int) int {
return if x < y { x } else { y } return if x < y {
x
} else {
y
}
} }
struct Cursor { struct Cursor {
@ -443,9 +456,7 @@ fn (mut a App) init_file() {
// 'vico: ' + // 'vico: ' +
a.tui.set_window_title(a.files[a.current_file]) a.tui.set_window_title(a.files[a.current_file])
mut b := a.ed mut b := a.ed
content := os.read_file(a.files[a.current_file]) or { content := os.read_file(a.files[a.current_file]) or { panic(err) }
panic(err)
}
b.put(content) b.put(content)
a.ed.cursor.pos_x = init_x a.ed.cursor.pos_x = init_x
a.ed.cursor.pos_y = init_y a.ed.cursor.pos_y = init_y
@ -573,12 +584,12 @@ fn main() {
mut a := &App{ mut a := &App{
files: files files: files
} }
a.tui = tui.init({ a.tui = tui.init(
user_data: a user_data: a
init_fn: init init_fn: init
frame_fn: frame frame_fn: frame
event_fn: event event_fn: event
capture_events: true capture_events: true
}) )
a.tui.run() a.tui.run() ?
} }

View File

@ -60,12 +60,12 @@ fn (mut v Vec) randomize(min_x int, min_y int, max_x int, max_y int) {
// part of snake's body representation // part of snake's body representation
struct BodyPart { struct BodyPart {
mut: mut:
pos Vec = { pos Vec = {
x: block_size x: block_size
y: block_size y: block_size
} }
color termui.Color = green color termui.Color = green
facing Orientation = .top facing Orientation = .top
} }
// snake representation // snake representation
@ -75,9 +75,9 @@ mut:
direction Orientation direction Orientation
body []BodyPart body []BodyPart
velocity Vec = Vec{ velocity Vec = Vec{
x: 0 x: 0
y: 0 y: 0
} }
} }
// length returns the snake's current length // length returns the snake's current length
@ -125,8 +125,16 @@ fn (mut s Snake) move() {
piece.facing = s.direction piece.facing = s.direction
new_x := piece.pos.x + s.velocity.x new_x := piece.pos.x + s.velocity.x
new_y := piece.pos.y + s.velocity.y new_y := piece.pos.y + s.velocity.y
piece.pos.x += if new_x > block_size && new_x < width - block_size { s.velocity.x } else { 0 } piece.pos.x += if new_x > block_size && new_x < width - block_size {
piece.pos.y += if new_y > block_size && new_y < height - block_size { s.velocity.y } else { 0 } s.velocity.x
} else {
0
}
piece.pos.y += if new_y > block_size && new_y < height - block_size {
s.velocity.y
} else {
0
}
} }
s.body[i] = piece s.body[i] = piece
} }
@ -205,10 +213,10 @@ fn (s Snake) check_overlap() bool {
fn (s Snake) check_out_of_bounds() bool { fn (s Snake) check_out_of_bounds() bool {
h := s.get_head() h := s.get_head()
return h.pos.x + s.velocity.x <= block_size || return h.pos.x + s.velocity.x <= block_size
h.pos.x + s.velocity.x > s.app.width - s.velocity.x || h.pos.y + s.velocity.y <= block_size || || h.pos.x + s.velocity.x > s.app.width - s.velocity.x
h.pos.y + s.velocity.y > || h.pos.y + s.velocity.y <= block_size
s.app.height - block_size - s.velocity.y || h.pos.y + s.velocity.y > s.app.height - block_size - s.velocity.y
} }
// draw draws the parts of the snake // draw draws the parts of the snake
@ -233,10 +241,10 @@ fn (s Snake) draw() {
// rat representation // rat representation
struct Rat { struct Rat {
mut: mut:
pos Vec = { pos Vec = {
x: block_size x: block_size
y: block_size y: block_size
} }
captured bool captured bool
color termui.Color = grey color termui.Color = grey
app &App app &App
@ -244,8 +252,8 @@ mut:
// randomize spawn the rat in a new spot within the playable field // randomize spawn the rat in a new spot within the playable field
fn (mut r Rat) randomize() { fn (mut r Rat) randomize() {
r.pos.randomize(2 * block_size + buffer, 2 * block_size + buffer, r.app.width - block_size - r.pos.randomize(2 * block_size + buffer, 2 * block_size + buffer, r.app.width - block_size - buffer,
buffer, r.app.height - block_size - buffer) r.app.height - block_size - buffer)
} }
struct App { struct App {
@ -255,7 +263,7 @@ mut:
rat Rat rat Rat
width int width int
height int height int
redraw bool = true redraw bool = true
state GameState = .game state GameState = .game
} }
@ -387,9 +395,8 @@ fn (mut a App) move_snake(direction Orientation) {
fn (a App) check_capture() bool { fn (a App) check_capture() bool {
snake_pos := a.snake.get_head().pos snake_pos := a.snake.get_head().pos
rat_pos := a.rat.pos rat_pos := a.rat.pos
return snake_pos.x <= rat_pos.x + block_size && return snake_pos.x <= rat_pos.x + block_size && snake_pos.x + block_size >= rat_pos.x
snake_pos.x + block_size >= rat_pos.x && snake_pos.y <= rat_pos.y + block_size && snake_pos.y + && snake_pos.y <= rat_pos.y + block_size&& snake_pos.y + block_size >= rat_pos.y
block_size >= rat_pos.y
} }
fn (mut a App) draw_snake() { fn (mut a App) draw_snake() {
@ -454,12 +461,12 @@ fn (mut a App) draw_gameover() {
} }
mut app := &App{} mut app := &App{}
app.termui = termui.init({ app.termui = termui.init(
user_data: app user_data: app
event_fn: event event_fn: event
frame_fn: frame frame_fn: frame
init_fn: init init_fn: init
hide_cursor: true hide_cursor: true
frame_rate: 10 frame_rate: 10
}) )
app.termui.run() app.termui.run() ?

View File

@ -12,22 +12,20 @@ fn main() {
println(term.green('client $ws.id ready')) println(term.green('client $ws.id ready'))
println('Write message and enter to send...') println('Write message and enter to send...')
for { for {
line := os.get_line() line := os.get_line()
if line == '' { if line == '' {
break break
} }
ws.write_str(line) ws.write_str(line) ?
}
ws.close(1000, 'normal') or {
println(term.red('panicing $err'))
} }
ws.close(1000, 'normal') or { println(term.red('panicing $err')) }
unsafe { unsafe {
ws.free() ws.free()
} }
} }
fn start_client() ?&websocket.Client { fn start_client() ?&websocket.Client {
mut ws := websocket.new_client('ws://localhost:30000')? mut ws := websocket.new_client('ws://localhost:30000') ?
// mut ws := websocket.new_client('wss://echo.websocket.org:443')? // mut ws := websocket.new_client('wss://echo.websocket.org:443')?
// use on_open_ref if you want to send any reference object // use on_open_ref if you want to send any reference object
ws.on_open(fn (mut ws websocket.Client) ? { ws.on_open(fn (mut ws websocket.Client) ? {
@ -49,12 +47,8 @@ fn start_client() ?&websocket.Client {
} }
}) })
ws.connect() or { ws.connect() or { println(term.red('error on connect: $err')) }
println(term.red('error on connect: $err'))
} go ws.listen() or { println(term.red('error on listen $err')) }
go ws.listen() or {
println(term.red('error on listen $err'))
}
return ws return ws
} }

View File

@ -259,7 +259,7 @@ fn (cmd Command) check_version_flag() {
version_flag := cmd.flags.get_bool('version') or { return } // ignore error and handle command normally version_flag := cmd.flags.get_bool('version') or { return } // ignore error and handle command normally
if version_flag { if version_flag {
version_cmd := cmd.commands.get('version') or { return } // ignore error and handle command normally version_cmd := cmd.commands.get('version') or { return } // ignore error and handle command normally
version_cmd.execute(version_cmd) version_cmd.execute(version_cmd) or { panic(err) }
exit(0) exit(0)
} }
} }
@ -280,7 +280,7 @@ fn (cmd Command) check_required_flags() {
pub fn (cmd Command) execute_help() { pub fn (cmd Command) execute_help() {
if cmd.commands.contains('help') { if cmd.commands.contains('help') {
help_cmd := cmd.commands.get('help') or { return } // ignore error and handle command normally help_cmd := cmd.commands.get('help') or { return } // ignore error and handle command normally
help_cmd.execute(help_cmd) help_cmd.execute(help_cmd) or { panic(err) }
} else { } else {
print(cmd.help_message()) print(cmd.help_message())
} }

View File

@ -22,7 +22,7 @@ fn test_vexe() {
fn test_can_compile_library() { fn test_can_compile_library() {
os.chdir(cfolder) os.chdir(cfolder)
os.rm(library_file_name) os.rm(library_file_name) or { }
res := v_compile('-d no_backtrace -o library -shared library.v') res := v_compile('-d no_backtrace -o library -shared library.v')
eprintln('res: $res') eprintln('res: $res')
assert os.is_file(library_file_name) assert os.is_file(library_file_name)
@ -34,7 +34,7 @@ fn test_can_compile_main_program() {
result := v_compile('run use.v') result := v_compile('run use.v')
eprintln('result: $result') eprintln('result: $result')
assert result.output.contains('res: 4') assert result.output.contains('res: 4')
os.rm(library_file_name) os.rm(library_file_name) or { }
} }
fn v_compile(vopts string) os.Result { fn v_compile(vopts string) os.Result {

View File

@ -10,16 +10,16 @@ const (
fn testsuite_begin() { fn testsuite_begin() {
eprintln('testsuite_begin, tfolder = $tfolder') eprintln('testsuite_begin, tfolder = $tfolder')
os.rmdir_all(tfolder) os.rmdir_all(tfolder) or { }
assert !os.is_dir(tfolder) assert !os.is_dir(tfolder)
os.mkdir_all(tfolder) os.mkdir_all(tfolder) or { panic(err) }
os.chdir(tfolder) os.chdir(tfolder)
assert os.is_dir(tfolder) assert os.is_dir(tfolder)
} }
fn testsuite_end() { fn testsuite_end() {
os.chdir(os.wd_at_startup) os.chdir(os.wd_at_startup)
os.rmdir_all(tfolder) os.rmdir_all(tfolder) or { }
assert !os.is_dir(tfolder) assert !os.is_dir(tfolder)
// eprintln('testsuite_end , tfolder = $tfolder removed.') // eprintln('testsuite_end , tfolder = $tfolder removed.')
} }
@ -38,9 +38,9 @@ fn test_temp_file() {
assert f.is_opened assert f.is_opened
// Test pattern // Test pattern
f.close() f.close()
f, path = util.temp_file({ f, path = util.temp_file(
pattern: 'some_*_test.file' pattern: 'some_*_test.file'
}) or { ) or {
assert false assert false
return return
} }
@ -58,9 +58,9 @@ fn test_temp_file() {
// Test custom path // Test custom path
prev_path = path prev_path = path
f.close() f.close()
f, path = util.temp_file({ f, path = util.temp_file(
path: tfolder path: tfolder
}) or { ) or {
assert false assert false
return return
} }
@ -88,9 +88,9 @@ fn test_temp_dir() {
assert writable assert writable
mut prev_path := path mut prev_path := path
// Test pattern // Test pattern
path = util.temp_dir({ path = util.temp_dir(
pattern: 'some_*_test_dir' pattern: 'some_*_test_dir'
}) or { ) or {
assert false assert false
return return
} }
@ -106,9 +106,9 @@ fn test_temp_dir() {
} }
// Test custom path // Test custom path
prev_path = path prev_path = path
path = util.temp_dir({ path = util.temp_dir(
path: tfolder path: tfolder
}) or { ) or {
assert false assert false
return return
} }

View File

@ -49,10 +49,10 @@ interface Logger {
// Log represents a logging object // Log represents a logging object
pub struct Log { pub struct Log {
mut: mut:
level Level level Level
output_label string output_label string
ofile os.File ofile os.File
output_to_file bool // if true output to file else use stdout/stderr. output_to_file bool // if true output to file else use stdout/stderr.
pub mut: pub mut:
output_file_name string // log output to this file output_file_name string // log output to this file
} }
@ -106,7 +106,7 @@ pub fn (mut l Log) close() {
fn (mut l Log) log_file(s string, level Level) { fn (mut l Log) log_file(s string, level Level) {
timestamp := time.now().format_ss() timestamp := time.now().format_ss()
e := tag_to_file(level) e := tag_to_file(level)
l.ofile.writeln('$timestamp [$e] $s') l.ofile.writeln('$timestamp [$e] $s') or { panic(err) }
} }
// log_cli writes log line `s` with `level` to stdout. // log_cli writes log line `s` with `level` to stdout.

View File

@ -36,7 +36,7 @@ pub fn socket_error(potential_code int) ?int {
pub fn wrap_error(error_code int) ? { pub fn wrap_error(error_code int) ? {
$if windows { $if windows {
enum_error := wsa_error(error_code) enum_error := wsa_error(error_code)
return error_with_code('socket error: $enum_error', error_code) return error_with_code('net: socket error: $enum_error', error_code)
} }
$else { $else {
if error_code == 0 { if error_code == 0 {

View File

@ -36,7 +36,7 @@ const (
struct DTP { struct DTP {
mut: mut:
conn net.TcpConn conn &net.TcpConn
reader io.BufferedReader reader io.BufferedReader
ip string ip string
port int port int
@ -56,31 +56,31 @@ fn (mut dtp DTP) read() ?[]byte {
} }
fn (mut dtp DTP) close() { fn (mut dtp DTP) close() {
dtp.conn.close() dtp.conn.close() or { panic(err) }
} }
struct FTP { struct FTP {
mut: mut:
conn net.TcpConn conn &net.TcpConn
reader io.BufferedReader reader io.BufferedReader
buffer_size int buffer_size int
} }
pub fn new() FTP { pub fn new() FTP {
mut f := FTP{} mut f := FTP{ conn: 0 }
f.buffer_size = 1024 f.buffer_size = 1024
return f return f
} }
fn (mut ftp FTP) write(data string) ? { fn (mut zftp FTP) write(data string) ? {
$if debug { $if debug {
println('FTP.v >>> $data') println('FTP.v >>> $data')
} }
ftp.conn.write('$data\r\n'.bytes()) ? zftp.conn.write('$data\r\n'.bytes()) ?
} }
fn (mut ftp FTP) read() ?(int, string) { fn (mut zftp FTP) read() ?(int, string) {
mut data := ftp.reader.read_line() ? mut data := zftp.reader.read_line() ?
$if debug { $if debug {
println('FTP.v <<< $data') println('FTP.v <<< $data')
} }
@ -90,7 +90,7 @@ fn (mut ftp FTP) read() ?(int, string) {
code := data[..3].int() code := data[..3].int()
if data[3] == `-` { if data[3] == `-` {
for { for {
data = ftp.reader.read_line() ? data = zftp.reader.read_line() ?
if data[..3].int() == code && data[3] != `-` { if data[..3].int() == code && data[3] != `-` {
break break
} }
@ -99,51 +99,51 @@ fn (mut ftp FTP) read() ?(int, string) {
return code, data return code, data
} }
pub fn (mut ftp FTP) connect(ip string) ?bool { pub fn (mut zftp FTP) connect(ip string) ?bool {
ftp.conn = net.dial_tcp('$ip:21') ? zftp.conn = net.dial_tcp('$ip:21') ?
ftp.reader = io.new_buffered_reader(reader: io.make_reader(ftp.conn)) zftp.reader = io.new_buffered_reader(reader: io.make_reader(zftp.conn))
code, _ := ftp.read() ? code, _ := zftp.read() ?
if code == connected { if code == ftp.connected {
return true return true
} }
return false return false
} }
pub fn (mut ftp FTP) login(user string, passwd string) ?bool { pub fn (mut zftp FTP) login(user string, passwd string) ?bool {
ftp.write('USER $user') or { zftp.write('USER $user') or {
$if debug { $if debug {
println('ERROR sending user') println('ERROR sending user')
} }
return false return false
} }
mut code, _ := ftp.read() ? mut code, _ := zftp.read() ?
if code == logged_in { if code == ftp.logged_in {
return true return true
} }
if code != specify_password { if code != ftp.specify_password {
return false return false
} }
ftp.write('PASS $passwd') or { zftp.write('PASS $passwd') or {
$if debug { $if debug {
println('ERROR sending password') println('ERROR sending password')
} }
return false return false
} }
code, _ = ftp.read() ? code, _ = zftp.read() ?
if code == logged_in { if code == ftp.logged_in {
return true return true
} }
return false return false
} }
pub fn (mut ftp FTP) close() ? { pub fn (mut zftp FTP) close() ? {
ftp.write('QUIT') ? zftp.write('QUIT') ?
ftp.conn.close() zftp.conn.close() ?
} }
pub fn (mut ftp FTP) pwd() ?string { pub fn (mut zftp FTP) pwd() ?string {
ftp.write('PWD') ? zftp.write('PWD') ?
_, data := ftp.read() ? _, data := zftp.read() ?
spl := data.split('"') // " spl := data.split('"') // "
if spl.len >= 2 { if spl.len >= 2 {
return spl[1] return spl[1]
@ -151,17 +151,17 @@ pub fn (mut ftp FTP) pwd() ?string {
return data return data
} }
pub fn (mut ftp FTP) cd(dir string) ? { pub fn (mut zftp FTP) cd(dir string) ? {
ftp.write('CWD $dir') or { return } zftp.write('CWD $dir') or { return }
mut code, mut data := ftp.read() ? mut code, mut data := zftp.read() ?
match int(code) { match int(code) {
denied { ftp.denied {
$if debug { $if debug {
println('CD $dir denied!') println('CD $dir denied!')
} }
} }
complete { ftp.complete {
code, data = ftp.read() ? code, data = zftp.read() ?
} }
else {} else {}
} }
@ -178,6 +178,7 @@ fn new_dtp(msg string) ?&DTP {
mut dtp := &DTP{ mut dtp := &DTP{
ip: ip ip: ip
port: port port: port
conn: 0
} }
conn := net.dial_tcp('$ip:$port') or { return error('Cannot connect to the data channel') } conn := net.dial_tcp('$ip:$port') or { return error('Cannot connect to the data channel') }
dtp.conn = conn dtp.conn = conn
@ -185,32 +186,32 @@ fn new_dtp(msg string) ?&DTP {
return dtp return dtp
} }
fn (mut ftp FTP) pasv() ?&DTP { fn (mut zftp FTP) pasv() ?&DTP {
ftp.write('PASV') ? zftp.write('PASV') ?
code, data := ftp.read() ? code, data := zftp.read() ?
$if debug { $if debug {
println('pass: $data') println('pass: $data')
} }
if code != passive_mode { if code != ftp.passive_mode {
return error('pasive mode not allowed') return error('pasive mode not allowed')
} }
dtp := new_dtp(data) ? dtp := new_dtp(data) ?
return dtp return dtp
} }
pub fn (mut ftp FTP) dir() ?[]string { pub fn (mut zftp FTP) dir() ?[]string {
mut dtp := ftp.pasv() or { return error('Cannot establish data connection') } mut dtp := zftp.pasv() or { return error('Cannot establish data connection') }
ftp.write('LIST') ? zftp.write('LIST') ?
code, _ := ftp.read() ? code, _ := zftp.read() ?
if code == denied { if code == ftp.denied {
return error('`LIST` denied') return error('`LIST` denied')
} }
if code != open_data_connection { if code != ftp.open_data_connection {
return error('Data channel empty') return error('Data channel empty')
} }
list_dir := dtp.read() ? list_dir := dtp.read() ?
result, _ := ftp.read() ? result, _ := zftp.read() ?
if result != close_data_connection { if result != ftp.close_data_connection {
println('`LIST` not ok') println('`LIST` not ok')
} }
dtp.close() dtp.close()
@ -225,14 +226,14 @@ pub fn (mut ftp FTP) dir() ?[]string {
return dir return dir
} }
pub fn (mut ftp FTP) get(file string) ?[]byte { pub fn (mut zftp FTP) get(file string) ?[]byte {
mut dtp := ftp.pasv() or { return error('Cannot stablish data connection') } mut dtp := zftp.pasv() or { return error('Cannot stablish data connection') }
ftp.write('RETR $file') ? zftp.write('RETR $file') ?
code, _ := ftp.read() ? code, _ := zftp.read() ?
if code == denied { if code == ftp.denied {
return error('Permission denied') return error('Permission denied')
} }
if code != open_data_connection { if code != ftp.open_data_connection {
return error('Data connection not ready') return error('Data connection not ready')
} }
blob := dtp.read() ? blob := dtp.read() ?

View File

@ -1,42 +1,49 @@
import net.ftp import net.ftp
// NB: this function makes network calls to external servers, fn test_ftp_cleint() {
// that is why it is not a very good idea to run it in CI. $if !network ? {
// If you want to run it manually, use `v -d network vlib/net/ftp/ftp_test.v` return
fn ftp_client_test_inside() ? {
$if !network ? { return }
mut ftp := ftp.new()
defer {
ftp.close()
} }
connect_result := ftp.connect('ftp.redhat.com')? // NB: this function makes network calls to external servers,
// that is why it is not a very good idea to run it in CI.
// If you want to run it manually, use:
// `v -d network vlib/net/ftp/ftp_test.v`
ftp_client_test_inside() or { panic(err) }
}
fn ftp_client_test_inside() ? {
mut zftp := ftp.new()
// eprintln(zftp)
defer {
zftp.close() or { panic(err) }
}
connect_result := zftp.connect('ftp.redhat.com') ?
assert connect_result assert connect_result
login_result := ftp.login('ftp', 'ftp')? login_result := zftp.login('ftp', 'ftp') ?
assert login_result assert login_result
pwd := ftp.pwd()? pwd := zftp.pwd() ?
assert pwd.len > 0 assert pwd.len > 0
ftp.cd('/') zftp.cd('/') or {
dir_list1 := ftp.dir() or { assert false
return
}
dir_list1 := zftp.dir() or {
assert false assert false
return return
} }
assert dir_list1.len > 0 assert dir_list1.len > 0
ftp.cd('/suse/linux/enterprise/11Server/en/SAT-TOOLS/SRPMS/') zftp.cd('/suse/linux/enterprise/11Server/en/SAT-TOOLS/SRPMS/') or {
dir_list2 := ftp.dir() or { assert false
return
}
dir_list2 := zftp.dir() or {
assert false assert false
return return
} }
assert dir_list2.len > 0 assert dir_list2.len > 0
blob := ftp.get('katello-host-tools-3.3.5-8.sles11_4sat.src.rpm') or { blob := zftp.get('katello-host-tools-3.3.5-8.sles11_4sat.src.rpm') or {
assert false assert false
return return
} }
assert blob.len > 0 assert blob.len > 0
} }
fn test_ftp_cleint() {
ftp_client_test_inside() or {
panic(err)
}
}

View File

@ -5,13 +5,11 @@ module http
import os import os
pub fn download_file(url string, out string)? { pub fn download_file(url string, out string) ? {
$if debug_http? { $if debug_http ? {
println('download file url=$url out=$out') println('download file url=$url out=$out')
} }
s := get(url) or { s := get(url) or { return error(err) }
return error(err) os.write_file(out, s.text) ?
}
os.write_file(out, s.text)
// download_file_with_progress(url, out, empty, empty) // download_file_with_progress(url, out, empty, empty)
} }

View File

@ -67,33 +67,48 @@ pub fn get(url string) ?Response {
} }
pub fn post(url string, data string) ?Response { pub fn post(url string, data string) ?Response {
return fetch_with_method(.post, url, data: data, headers: { return fetch_with_method(.post, url,
'Content-Type': content_type_default data: data
}) headers: {
'Content-Type': http.content_type_default
}
)
} }
pub fn post_json(url string, data string) ?Response { pub fn post_json(url string, data string) ?Response {
return fetch_with_method(.post, url, data: data, headers: { return fetch_with_method(.post, url,
data: data
headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}) }
)
} }
pub fn post_form(url string, data map[string]string) ?Response { pub fn post_form(url string, data map[string]string) ?Response {
return fetch_with_method(.post, url, headers: { return fetch_with_method(.post, url,
headers: {
'Content-Type': 'application/x-www-form-urlencoded' 'Content-Type': 'application/x-www-form-urlencoded'
}, data: url_encode_form_data(data)) }
data: url_encode_form_data(data)
)
} }
pub fn put(url string, data string) ?Response { pub fn put(url string, data string) ?Response {
return fetch_with_method(.put, url, data: data, headers: { return fetch_with_method(.put, url,
'Content-Type': content_type_default data: data
}) headers: {
'Content-Type': http.content_type_default
}
)
} }
pub fn patch(url string, data string) ?Response { pub fn patch(url string, data string) ?Response {
return fetch_with_method(.patch, url, data: data, headers: { return fetch_with_method(.patch, url,
'Content-Type': content_type_default data: data
}) headers: {
'Content-Type': http.content_type_default
}
)
} }
pub fn head(url string) ?Response { pub fn head(url string) ?Response {
@ -165,11 +180,11 @@ fn build_url_from_fetch(_url string, config FetchConfig) ?string {
} }
fn (mut req Request) free() { fn (mut req Request) free() {
unsafe {req.headers.free()} unsafe { req.headers.free() }
} }
fn (mut resp Response) free() { fn (mut resp Response) free() {
unsafe {resp.headers.free()} unsafe { resp.headers.free() }
} }
// add_header adds the key and value of an HTTP request header // add_header adds the key and value of an HTTP request header
@ -199,8 +214,8 @@ pub fn (req &Request) do() ?Response {
mut resp := Response{} mut resp := Response{}
mut no_redirects := 0 mut no_redirects := 0
for { for {
if no_redirects == max_redirects { if no_redirects == http.max_redirects {
return error('http.request.do: maximum number of redirects reached ($max_redirects)') return error('http.request.do: maximum number of redirects reached ($http.max_redirects)')
} }
qresp := req.method_and_url_to_response(req.method, rurl) ? qresp := req.method_and_url_to_response(req.method, rurl) ?
resp = qresp resp = qresp
@ -366,7 +381,7 @@ fn (req &Request) http_do(host string, method Method, path string) ?Response {
// TODO this really needs to be exposed somehow // TODO this really needs to be exposed somehow
client.write(s.bytes()) ? client.write(s.bytes()) ?
mut bytes := io.read_all(reader: client) ? mut bytes := io.read_all(reader: client) ?
client.close() client.close() ?
return parse_response(bytes.bytestr()) return parse_response(bytes.bytestr())
} }

View File

@ -96,8 +96,8 @@ pub fn (mut c Client) send(config Mail) ? {
// quit closes the connection to the server // quit closes the connection to the server
pub fn (mut c Client) quit() ? { pub fn (mut c Client) quit() ? {
c.send_str('QUIT\r\n') c.send_str('QUIT\r\n') ?
c.expect_reply(.close) c.expect_reply(.close) ?
c.conn.close() ? c.conn.close() ?
c.is_open = false c.is_open = false
} }
@ -166,7 +166,7 @@ fn (mut c Client) send_mailto(to string) ? {
fn (mut c Client) send_data() ? { fn (mut c Client) send_data() ? {
c.send_str('DATA\r\n') ? c.send_str('DATA\r\n') ?
c.expect_reply(.mail_start) c.expect_reply(.mail_start) ?
} }
fn (mut c Client) send_body(cfg Mail) ? { fn (mut c Client) send_body(cfg Mail) ? {

View File

@ -22,8 +22,8 @@ pub fn dial_tcp(address string) ?&TcpConn {
s.connect(address) ? s.connect(address) ?
return &TcpConn{ return &TcpConn{
sock: s sock: s
read_timeout: tcp_default_read_timeout read_timeout: net.tcp_default_read_timeout
write_timeout: tcp_default_write_timeout write_timeout: net.tcp_default_write_timeout
} }
} }
@ -35,7 +35,8 @@ pub fn (mut c TcpConn) close() ? {
// write_ptr blocks and attempts to write all data // write_ptr blocks and attempts to write all data
pub fn (mut c TcpConn) write_ptr(b byteptr, len int) ? { pub fn (mut c TcpConn) write_ptr(b byteptr, len int) ? {
$if trace_tcp ? { $if trace_tcp ? {
eprintln('>>> TcpConn.write_ptr | c.sock.handle: $c.sock.handle | b: ${ptr_str(b)} len: $len |\n' + eprintln(
'>>> TcpConn.write_ptr | c.sock.handle: $c.sock.handle | b: ${ptr_str(b)} len: $len |\n' +
unsafe { b.vstring_with_len(len) }) unsafe { b.vstring_with_len(len) })
} }
unsafe { unsafe {
@ -48,7 +49,7 @@ pub fn (mut c TcpConn) write_ptr(b byteptr, len int) ? {
if sent < 0 { if sent < 0 {
code := error_code() code := error_code()
if code == int(error_ewouldblock) { if code == int(error_ewouldblock) {
c.wait_for_write() c.wait_for_write() ?
continue continue
} else { } else {
wrap_error(code) ? wrap_error(code) ?
@ -164,9 +165,9 @@ pub fn (c &TcpConn) peer_ip() ?string {
return res return res
} }
pub fn (c &TcpConn) str() string { pub fn (c TcpConn) str() string {
// TODO s := c.sock.str().replace('\n', ' ').replace(' ', ' ')
return 'TcpConn {write_deadline: $c.write_deadline, read_deadline: $c.read_deadline, read_timeout: $c.read_timeout, write_timeout: $c.write_timeout, sock: $c.sock}' return 'TcpConn{ write_deadline: $c.write_deadline, read_deadline: $c.read_deadline, read_timeout: $c.read_timeout, write_timeout: $c.write_timeout, sock: $s }'
} }
pub struct TcpListener { pub struct TcpListener {
@ -213,8 +214,8 @@ pub fn (mut l TcpListener) accept() ?&TcpConn {
new_sock := tcp_socket_from_handle(new_handle) ? new_sock := tcp_socket_from_handle(new_handle) ?
return &TcpConn{ return &TcpConn{
sock: new_sock sock: new_sock
read_timeout: tcp_default_read_timeout read_timeout: net.tcp_default_read_timeout
write_timeout: tcp_default_write_timeout write_timeout: net.tcp_default_write_timeout
} }
} }
@ -266,7 +267,7 @@ fn new_tcp_socket() ?TcpSocket {
t := true t := true
socket_error(C.ioctlsocket(sockfd, fionbio, &t)) ? socket_error(C.ioctlsocket(sockfd, fionbio, &t)) ?
} $else { } $else {
socket_error(C.fcntl(sockfd, C.F_SETFL, C.fcntl(sockfd, C.F_GETFL) | C.O_NONBLOCK)) socket_error(C.fcntl(sockfd, C.F_SETFL, C.fcntl(sockfd, C.F_GETFL) | C.O_NONBLOCK)) ?
} }
return s return s
} }
@ -281,7 +282,7 @@ fn tcp_socket_from_handle(sockfd int) ?TcpSocket {
t := true t := true
socket_error(C.ioctlsocket(sockfd, fionbio, &t)) ? socket_error(C.ioctlsocket(sockfd, fionbio, &t)) ?
} $else { } $else {
socket_error(C.fcntl(sockfd, C.F_SETFL, C.fcntl(sockfd, C.F_GETFL) | C.O_NONBLOCK)) socket_error(C.fcntl(sockfd, C.F_SETFL, C.fcntl(sockfd, C.F_GETFL) | C.O_NONBLOCK)) ?
} }
return s return s
} }
@ -322,12 +323,12 @@ fn (mut s TcpSocket) connect(a string) ? {
return none return none
} }
_ := error_code() _ := error_code()
write_result := s.@select(.write, connect_timeout) ? write_result := s.@select(.write, net.connect_timeout) ?
if write_result { if write_result {
// succeeded // succeeded
return none return none
} }
except_result := s.@select(.except, connect_timeout) ? except_result := s.@select(.except, net.connect_timeout) ?
if except_result { if except_result {
return err_connect_failed return err_connect_failed
} }

View File

@ -64,7 +64,10 @@ fn test_socket_write_and_read() {
message1 := 'a message 1' message1 := 'a message 1'
socket.write_str(message1) or { assert false } socket.write_str(message1) or { assert false }
mut rbuf := []byte{len: message1.len} mut rbuf := []byte{len: message1.len}
client.read(mut rbuf) client.read(mut rbuf) or {
assert false
return
}
line := rbuf.bytestr() line := rbuf.bytestr()
assert line == message1 assert line == message1
} }
@ -127,8 +130,14 @@ fn test_socket_read_line_long_line_without_eol() {
cleanup(mut server, mut client, mut socket) cleanup(mut server, mut client, mut socket)
} }
message := strings.repeat_string('123', 400) message := strings.repeat_string('123', 400)
socket.write_str(message) socket.write_str(message) or {
socket.write_str('\n') assert false
return
}
socket.write_str('\n') or {
assert false
return
}
line := reader.read_line() or { line := reader.read_line() or {
assert false assert false
return return

View File

@ -33,8 +33,8 @@ pub fn dial_udp(laddr string, raddr string) ?&UdpConn {
} }
return &UdpConn{ return &UdpConn{
sock: sock sock: sock
read_timeout: udp_default_read_timeout read_timeout: net.udp_default_read_timeout
write_timeout: udp_default_write_timeout write_timeout: net.udp_default_write_timeout
} }
} }
@ -162,8 +162,8 @@ pub fn listen_udp(port int) ?&UdpConn {
s := new_udp_socket(port) ? s := new_udp_socket(port) ?
return &UdpConn{ return &UdpConn{
sock: s sock: s
read_timeout: udp_default_read_timeout read_timeout: net.udp_default_read_timeout
write_timeout: udp_default_write_timeout write_timeout: net.udp_default_write_timeout
} }
} }
@ -183,7 +183,7 @@ fn new_udp_socket(local_port int) ?&UdpSocket {
t := true t := true
socket_error(C.ioctlsocket(sockfd, fionbio, &t)) ? socket_error(C.ioctlsocket(sockfd, fionbio, &t)) ?
} $else { } $else {
socket_error(C.fcntl(sockfd, C.F_SETFD, C.O_NONBLOCK)) socket_error(C.fcntl(sockfd, C.F_SETFD, C.O_NONBLOCK)) ?
} }
// In UDP we always have to bind to a port // In UDP we always have to bind to a port
validate_port(local_port) ? validate_port(local_port) ?

View File

@ -53,8 +53,8 @@ fn should_escape(c byte, mode EncodingMode) bool {
// we could possibly allow, and parse will reject them if we // we could possibly allow, and parse will reject them if we
// escape them (because hosts can`t use %-encoding for // escape them (because hosts can`t use %-encoding for
// ASCII bytes). // ASCII bytes).
if c in if
[`!`, `$`, `&`, `\\`, `(`, `)`, `*`, `+`, `,`, `;`, `=`, `:`, `[`, `]`, `<`, `>`, `"`] { c in [`!`, `$`, `&`, `\\`, `(`, `)`, `*`, `+`, `,`, `;`, `=`, `:`, `[`, `]`, `<`, `>`, `"`] {
return false return false
} }
} }
@ -162,7 +162,7 @@ fn unescape(s_ string, mode EncodingMode) ?string {
if s.len > 3 { if s.len > 3 {
s = s[..3] s = s[..3]
} }
return error(error_msg(err_msg_escape, s)) return error(error_msg(urllib.err_msg_escape, s))
} }
// Per https://tools.ietf.org/html/rfc3986#page-21 // Per https://tools.ietf.org/html/rfc3986#page-21
// in the host component %-encoding can only be used // in the host component %-encoding can only be used
@ -171,7 +171,7 @@ fn unescape(s_ string, mode EncodingMode) ?string {
// introduces %25 being allowed to escape a percent sign // introduces %25 being allowed to escape a percent sign
// in IPv6 scoped-address literals. Yay. // in IPv6 scoped-address literals. Yay.
if mode == .encode_host && unhex(s[i + 1]) < 8 && s[i..i + 3] != '%25' { if mode == .encode_host && unhex(s[i + 1]) < 8 && s[i..i + 3] != '%25' {
return error(error_msg(err_msg_escape, s[i..i + 3])) return error(error_msg(urllib.err_msg_escape, s[i..i + 3]))
} }
if mode == .encode_zone { if mode == .encode_zone {
// RFC 6874 says basically 'anything goes' for zone identifiers // RFC 6874 says basically 'anything goes' for zone identifiers
@ -183,7 +183,7 @@ fn unescape(s_ string, mode EncodingMode) ?string {
// But Windows puts spaces here! Yay. // But Windows puts spaces here! Yay.
v := ((unhex(s[i + 1]) << byte(4)) | unhex(s[i + 2])) v := ((unhex(s[i + 1]) << byte(4)) | unhex(s[i + 2]))
if s[i..i + 3] != '%25' && v != ` ` && should_escape(v, .encode_host) { if s[i..i + 3] != '%25' && v != ` ` && should_escape(v, .encode_host) {
error(error_msg(err_msg_escape, s[i..i + 3])) error(error_msg(urllib.err_msg_escape, s[i..i + 3]))
} }
} }
i += 3 i += 3
@ -193,9 +193,8 @@ fn unescape(s_ string, mode EncodingMode) ?string {
i++ i++
} }
else { else {
if (mode == .encode_host || if (mode == .encode_host || mode == .encode_zone) && s[i] < 0x80
mode == .encode_zone) && && should_escape(s[i], mode) {
s[i] < 0x80 && should_escape(s[i], mode) {
error(error_msg('unescape: invalid character in host name', s[i..i + 1])) error(error_msg('unescape: invalid character in host name', s[i..i + 1]))
} }
i++ i++
@ -429,11 +428,12 @@ fn split(s string, sep byte, cutc bool) (string, string) {
pub fn parse(rawurl string) ?URL { pub fn parse(rawurl string) ?URL {
// Cut off #frag // Cut off #frag
u, frag := split(rawurl, `#`, true) u, frag := split(rawurl, `#`, true)
mut url := parse_url(u, false) or { return error(error_msg(err_msg_parse, u)) } mut url := parse_url(u, false) or { return error(error_msg(urllib.err_msg_parse, u)) }
if frag == '' { if frag == '' {
return url return url
} }
f := unescape(frag, .encode_fragment) or { return error(error_msg(err_msg_parse, u)) } f := unescape(frag, .encode_fragment) or { return error(error_msg(urllib.err_msg_parse,
u)) }
url.fragment = f url.fragment = f
return url return url
} }
@ -570,7 +570,7 @@ fn parse_host(host string) ?string {
// parse an IP-Literal in RFC 3986 and RFC 6874. // parse an IP-Literal in RFC 3986 and RFC 6874.
// E.g., '[fe80::1]', '[fe80::1%25en0]', '[fe80::1]:80'. // E.g., '[fe80::1]', '[fe80::1%25en0]', '[fe80::1]:80'.
mut i := host.last_index(']') or { mut i := host.last_index(']') or {
return error(error_msg("parse_host: missing \']\' in host", '')) return error(error_msg("parse_host: missing ']' in host", ''))
} }
mut colon_port := host[i + 1..] mut colon_port := host[i + 1..]
if !valid_optional_port(colon_port) { if !valid_optional_port(colon_port) {
@ -785,7 +785,7 @@ pub fn parse_query(query string) ?Values {
// but any errors will be silent // but any errors will be silent
fn parse_query_silent(query string) Values { fn parse_query_silent(query string) Values {
mut m := new_values() mut m := new_values()
parse_query_values(mut m, query) parse_query_values(mut m, query) or { }
return m return m
} }
@ -1029,7 +1029,8 @@ pub fn valid_userinfo(s string) bool {
continue continue
} }
match r { match r {
`-`, `.`, `_`, `:`, `~`, `!`, `$`, `&`, `\\`, `(`, `)`, `*`, `+`, `,`, `;`, `=`, `%`, `@` { `-`, `.`, `_`, `:`, `~`, `!`, `$`, `&`, `\\`, `(`, `)`, `*`, `+`, `,`, `;`, `=`, `%`,
`@` {
continue continue
} }
else { else {

View File

@ -9,16 +9,16 @@ const (
fn testsuite_begin() { fn testsuite_begin() {
eprintln('testsuite_begin, tfolder = $tfolder') eprintln('testsuite_begin, tfolder = $tfolder')
os.rmdir_all(tfolder) os.rmdir_all(tfolder) or { }
assert !os.is_dir(tfolder) assert !os.is_dir(tfolder)
os.mkdir_all(tfolder) os.mkdir_all(tfolder) or { panic(err) }
os.chdir(tfolder) os.chdir(tfolder)
assert os.is_dir(tfolder) assert os.is_dir(tfolder)
} }
fn testsuite_end() { fn testsuite_end() {
os.chdir(os.wd_at_startup) os.chdir(os.wd_at_startup)
os.rmdir_all(tfolder) os.rmdir_all(tfolder) or { panic(err) }
assert !os.is_dir(tfolder) assert !os.is_dir(tfolder)
} }
@ -27,7 +27,7 @@ fn test_inode_file_type() {
mut file := os.open_file(filename, 'w', 0o600) or { return } mut file := os.open_file(filename, 'w', 0o600) or { return }
file.close() file.close()
mode := os.inode(filename) mode := os.inode(filename)
os.rm(filename) os.rm(filename) or { panic(err) }
assert mode.typ == .regular assert mode.typ == .regular
} }
@ -36,7 +36,7 @@ fn test_inode_file_owner_permission() {
mut file := os.open_file(filename, 'w', 0o600) or { return } mut file := os.open_file(filename, 'w', 0o600) or { return }
file.close() file.close()
mode := os.inode(filename) mode := os.inode(filename)
os.rm(filename) os.rm(filename) or { }
assert mode.owner.read assert mode.owner.read
assert mode.owner.write assert mode.owner.write
assert !mode.owner.execute assert !mode.owner.execute

View File

@ -46,7 +46,7 @@ pub fn cp_all(src string, dst string, overwrite bool) ? {
} }
if exists(adjusted_path) { if exists(adjusted_path) {
if overwrite { if overwrite {
rm(adjusted_path) rm(adjusted_path) ?
} else { } else {
return error('Destination file path already exist') return error('Destination file path already exist')
} }
@ -65,7 +65,7 @@ pub fn cp_all(src string, dst string, overwrite bool) ? {
mkdir(dp) ? mkdir(dp) ?
} }
cp_all(sp, dp, overwrite) or { cp_all(sp, dp, overwrite) or {
rmdir(dp) rmdir(dp) or { return error(err) }
return error(err) return error(err)
} }
} }
@ -144,7 +144,7 @@ pub fn file_exists(_path string) bool {
[deprecated] [deprecated]
pub fn rmdir_recursive(path string) { pub fn rmdir_recursive(path string) {
eprintln('warning: `os.rmdir_recursive` has been deprecated, use `os.rmdir_all` instead') eprintln('warning: `os.rmdir_recursive` has been deprecated, use `os.rmdir_all` instead')
rmdir_all(path) rmdir_all(path) or { panic(err) }
} }
// rmdir_all recursively removes the specified directory. // rmdir_all recursively removes the specified directory.
@ -154,7 +154,7 @@ pub fn rmdir_all(path string) ? {
for item in items { for item in items {
fullpath := join_path(path, item) fullpath := join_path(path, item)
if is_dir(fullpath) { if is_dir(fullpath) {
rmdir_all(fullpath) rmdir_all(fullpath) or { ret_err = err }
} }
rm(fullpath) or { ret_err = err } rm(fullpath) or { ret_err = err }
} }
@ -315,7 +315,7 @@ pub fn home_dir() string {
// write_file writes `text` data to a file in `path`. // write_file writes `text` data to a file in `path`.
pub fn write_file(path string, text string) ? { pub fn write_file(path string, text string) ? {
mut f := create(path) ? mut f := create(path) ?
f.write(text.bytes()) f.write(text.bytes()) ?
f.close() f.close()
} }

View File

@ -280,7 +280,7 @@ pub fn is_writable_folder(folder string) ?bool {
} }
C.close(x) C.close(x)
} }
rm(tmp_perm_check) rm(tmp_perm_check) ?
return true return true
} }

View File

@ -13,9 +13,9 @@ const args_at_start = os.args.clone()
fn testsuite_begin() { fn testsuite_begin() {
eprintln('testsuite_begin, tfolder = $tfolder') eprintln('testsuite_begin, tfolder = $tfolder')
os.rmdir_all(tfolder) os.rmdir_all(tfolder) or { }
assert !os.is_dir(tfolder) assert !os.is_dir(tfolder)
os.mkdir_all(tfolder) os.mkdir_all(tfolder) or { panic(err) }
os.chdir(tfolder) os.chdir(tfolder)
assert os.is_dir(tfolder) assert os.is_dir(tfolder)
// println('args_at_start: $args_at_start') // println('args_at_start: $args_at_start')
@ -25,7 +25,7 @@ fn testsuite_begin() {
fn testsuite_end() { fn testsuite_end() {
os.chdir(os.wd_at_startup) os.chdir(os.wd_at_startup)
os.rmdir_all(tfolder) os.rmdir_all(tfolder) or { }
assert !os.is_dir(tfolder) assert !os.is_dir(tfolder)
// eprintln('testsuite_end , tfolder = $tfolder removed.') // eprintln('testsuite_end , tfolder = $tfolder removed.')
} }
@ -38,12 +38,12 @@ fn test_open_file() {
os.File{} os.File{}
} }
mut file := os.open_file(filename, 'w+', 0o666) or { panic(err) } mut file := os.open_file(filename, 'w+', 0o666) or { panic(err) }
file.write_str(hello) file.write_str(hello) or { panic(err) }
file.close() file.close()
assert hello.len == os.file_size(filename) assert hello.len == os.file_size(filename)
read_hello := os.read_file(filename) or { panic('error reading file $filename') } read_hello := os.read_file(filename) or { panic('error reading file $filename') }
assert hello == read_hello assert hello == read_hello
os.rm(filename) os.rm(filename) or { panic(err) }
} }
fn test_open_file_binary() { fn test_open_file_binary() {
@ -60,7 +60,7 @@ fn test_open_file_binary() {
assert hello.len == os.file_size(filename) assert hello.len == os.file_size(filename)
read_hello := os.read_bytes(filename) or { panic('error reading file $filename') } read_hello := os.read_bytes(filename) or { panic('error reading file $filename') }
assert bytes == read_hello assert bytes == read_hello
os.rm(filename) os.rm(filename) or { panic(err) }
} }
// fn test_file_get_line() { // fn test_file_get_line() {
@ -87,23 +87,23 @@ fn test_create_file() {
filename := './test1.txt' filename := './test1.txt'
hello := 'hello world!' hello := 'hello world!'
mut f := os.create(filename) or { panic(err) } mut f := os.create(filename) or { panic(err) }
f.write_str(hello) f.write_str(hello) or { panic(err) }
f.close() f.close()
assert hello.len == os.file_size(filename) assert hello.len == os.file_size(filename)
os.rm(filename) os.rm(filename) or { panic(err) }
} }
fn test_is_file() { fn test_is_file() {
// Setup // Setup
work_dir := os.join_path(os.getwd(), 'is_file_test') work_dir := os.join_path(os.getwd(), 'is_file_test')
os.mkdir_all(work_dir) os.mkdir_all(work_dir) or { panic(err) }
tfile := os.join_path(work_dir, 'tmp_file') tfile := os.join_path(work_dir, 'tmp_file')
// Test things that shouldn't be a file // Test things that shouldn't be a file
assert os.is_file(work_dir) == false assert os.is_file(work_dir) == false
assert os.is_file('non-existent_file.tmp') == false assert os.is_file('non-existent_file.tmp') == false
// Test file // Test file
tfile_content := 'temporary file' tfile_content := 'temporary file'
os.write_file(tfile, tfile_content) os.write_file(tfile, tfile_content) or { panic(err) }
assert os.is_file(tfile) assert os.is_file(tfile)
// Test dir symlinks // Test dir symlinks
$if windows { $if windows {
@ -126,11 +126,11 @@ fn test_is_file() {
fn test_write_and_read_string_to_file() { fn test_write_and_read_string_to_file() {
filename := './test1.txt' filename := './test1.txt'
hello := 'hello world!' hello := 'hello world!'
os.write_file(filename, hello) os.write_file(filename, hello) or { panic(err) }
assert hello.len == os.file_size(filename) assert hello.len == os.file_size(filename)
read_hello := os.read_file(filename) or { panic('error reading file $filename') } read_hello := os.read_file(filename) or { panic('error reading file $filename') }
assert hello == read_hello assert hello == read_hello
os.rm(filename) os.rm(filename) or { panic(err) }
} }
// test_write_and_read_bytes checks for regressions made in the functions // test_write_and_read_bytes checks for regressions made in the functions
@ -166,7 +166,7 @@ fn test_write_and_read_bytes() {
assert nread == 0 assert nread == 0
file_read.close() file_read.close()
// We finally delete the test file. // We finally delete the test file.
os.rm(file_name) os.rm(file_name) or { panic(err) }
} }
fn test_create_and_delete_folder() { fn test_create_and_delete_folder() {
@ -175,7 +175,7 @@ fn test_create_and_delete_folder() {
assert os.is_dir(folder) assert os.is_dir(folder)
folder_contents := os.ls(folder) or { panic(err) } folder_contents := os.ls(folder) or { panic(err) }
assert folder_contents.len == 0 assert folder_contents.len == 0
os.rmdir(folder) os.rmdir(folder) or { panic(err) }
folder_exists := os.is_dir(folder) folder_exists := os.is_dir(folder)
assert folder_exists == false assert folder_exists == false
} }
@ -191,61 +191,61 @@ fn test_walk() {
folder := 'test_walk' folder := 'test_walk'
os.mkdir(folder) or { panic(err) } os.mkdir(folder) or { panic(err) }
file1 := folder + os.path_separator + 'test1' file1 := folder + os.path_separator + 'test1'
os.write_file(file1, 'test-1') os.write_file(file1, 'test-1') or { panic(err) }
os.walk(folder, walk_callback) os.walk(folder, walk_callback)
os.rm(file1) os.rm(file1) or { panic(err) }
os.rmdir(folder) os.rmdir(folder) or { panic(err) }
} }
fn test_cp() { fn test_cp() {
old_file_name := 'cp_example.txt' old_file_name := 'cp_example.txt'
new_file_name := 'cp_new_example.txt' new_file_name := 'cp_new_example.txt'
os.write_file(old_file_name, 'Test data 1 2 3, V is awesome #$%^[]!~') os.write_file(old_file_name, 'Test data 1 2 3, V is awesome #$%^[]!~') or { panic(err) }
os.cp(old_file_name, new_file_name) or { panic('$err: errcode: $errcode') } os.cp(old_file_name, new_file_name) or { panic('$err: errcode: $errcode') }
old_file := os.read_file(old_file_name) or { panic(err) } old_file := os.read_file(old_file_name) or { panic(err) }
new_file := os.read_file(new_file_name) or { panic(err) } new_file := os.read_file(new_file_name) or { panic(err) }
assert old_file == new_file assert old_file == new_file
os.rm(old_file_name) os.rm(old_file_name) or { panic(err) }
os.rm(new_file_name) os.rm(new_file_name) or { panic(err) }
} }
fn test_mv() { fn test_mv() {
work_dir := os.join_path(os.getwd(), 'mv_test') work_dir := os.join_path(os.getwd(), 'mv_test')
os.mkdir_all(work_dir) os.mkdir_all(work_dir) or { panic(err) }
// Setup test files // Setup test files
tfile1 := os.join_path(work_dir, 'file') tfile1 := os.join_path(work_dir, 'file')
tfile2 := os.join_path(work_dir, 'file.test') tfile2 := os.join_path(work_dir, 'file.test')
tfile3 := os.join_path(work_dir, 'file.3') tfile3 := os.join_path(work_dir, 'file.3')
tfile_content := 'temporary file' tfile_content := 'temporary file'
os.write_file(tfile1, tfile_content) os.write_file(tfile1, tfile_content) or { panic(err) }
os.write_file(tfile2, tfile_content) os.write_file(tfile2, tfile_content) or { panic(err) }
// Setup test dirs // Setup test dirs
tdir1 := os.join_path(work_dir, 'dir') tdir1 := os.join_path(work_dir, 'dir')
tdir2 := os.join_path(work_dir, 'dir2') tdir2 := os.join_path(work_dir, 'dir2')
tdir3 := os.join_path(work_dir, 'dir3') tdir3 := os.join_path(work_dir, 'dir3')
mkdir(tdir1) os.mkdir(tdir1) or { panic(err) }
mkdir(tdir2) os.mkdir(tdir2) or { panic(err) }
// Move file with no extension to dir // Move file with no extension to dir
os.mv(tfile1, tdir1) os.mv(tfile1, tdir1) or { panic(err) }
mut expected := os.join_path(tdir1, 'file') mut expected := os.join_path(tdir1, 'file')
assert os.exists(expected) && !is_dir(expected) == true assert os.exists(expected) && !is_dir(expected) == true
// Move dir with contents to other dir // Move dir with contents to other dir
os.mv(tdir1, tdir2) os.mv(tdir1, tdir2) or { panic(err) }
expected = os.join_path(tdir2, 'dir') expected = os.join_path(tdir2, 'dir')
assert os.exists(expected) && is_dir(expected) == true assert os.exists(expected) && is_dir(expected) == true
expected = os.join_path(tdir2, 'dir', 'file') expected = os.join_path(tdir2, 'dir', 'file')
assert os.exists(expected) && !is_dir(expected) == true assert os.exists(expected) && !is_dir(expected) == true
// Move dir with contents to other dir (by renaming) // Move dir with contents to other dir (by renaming)
os.mv(os.join_path(tdir2, 'dir'), tdir3) os.mv(os.join_path(tdir2, 'dir'), tdir3) or { panic(err) }
expected = tdir3 expected = tdir3
assert os.exists(expected) && is_dir(expected) == true assert os.exists(expected) && is_dir(expected) == true
assert os.is_dir_empty(tdir2) == true assert os.is_dir_empty(tdir2) == true
// Move file with extension to dir // Move file with extension to dir
os.mv(tfile2, tdir2) os.mv(tfile2, tdir2) or { panic(err) }
expected = os.join_path(tdir2, 'file.test') expected = os.join_path(tdir2, 'file.test')
assert os.exists(expected) && !is_dir(expected) == true assert os.exists(expected) && !is_dir(expected) == true
// Move file to dir (by renaming) // Move file to dir (by renaming)
os.mv(os.join_path(tdir2, 'file.test'), tfile3) os.mv(os.join_path(tdir2, 'file.test'), tfile3) or { panic(err) }
expected = tfile3 expected = tfile3
assert os.exists(expected) && !is_dir(expected) == true assert os.exists(expected) && !is_dir(expected) == true
} }
@ -253,14 +253,14 @@ fn test_mv() {
fn test_cp_r() { fn test_cp_r() {
// fileX -> dir/fileX // fileX -> dir/fileX
// NB: clean up of the files happens inside the cleanup_leftovers function // NB: clean up of the files happens inside the cleanup_leftovers function
os.write_file('ex1.txt', 'wow!') os.write_file('ex1.txt', 'wow!') or { panic(err) }
os.mkdir('ex') or { panic(err) } os.mkdir('ex') or { panic(err) }
os.cp_all('ex1.txt', 'ex', false) or { panic(err) } os.cp_all('ex1.txt', 'ex', false) or { panic(err) }
old := os.read_file('ex1.txt') or { panic(err) } old := os.read_file('ex1.txt') or { panic(err) }
new := os.read_file('ex/ex1.txt') or { panic(err) } new := os.read_file('ex/ex1.txt') or { panic(err) }
assert old == new assert old == new
os.mkdir('ex/ex2') or { panic(err) } os.mkdir('ex/ex2') or { panic(err) }
os.write_file('ex2.txt', 'great!') os.write_file('ex2.txt', 'great!') or { panic(err) }
os.cp_all('ex2.txt', 'ex/ex2', false) or { panic(err) } os.cp_all('ex2.txt', 'ex/ex2', false) or { panic(err) }
old2 := os.read_file('ex2.txt') or { panic(err) } old2 := os.read_file('ex2.txt') or { panic(err) }
new2 := os.read_file('ex/ex2/ex2.txt') or { panic(err) } new2 := os.read_file('ex/ex2/ex2.txt') or { panic(err) }
@ -274,12 +274,12 @@ fn test_tmpdir() {
assert t.len > 0 assert t.len > 0
assert os.is_dir(t) assert os.is_dir(t)
tfile := t + os.path_separator + 'tmpfile.txt' tfile := t + os.path_separator + 'tmpfile.txt'
os.rm(tfile) // just in case os.rm(tfile) or { } // just in case
tfile_content := 'this is a temporary file' tfile_content := 'this is a temporary file'
os.write_file(tfile, tfile_content) os.write_file(tfile, tfile_content) or { panic(err) }
tfile_content_read := os.read_file(tfile) or { panic(err) } tfile_content_read := os.read_file(tfile) or { panic(err) }
assert tfile_content_read == tfile_content assert tfile_content_read == tfile_content
os.rm(tfile) os.rm(tfile) or { panic(err) }
} }
fn test_is_writable_folder() { fn test_is_writable_folder() {
@ -299,15 +299,15 @@ fn test_make_symlink_check_is_link_and_remove_symlink() {
} }
folder := 'tfolder' folder := 'tfolder'
symlink := 'tsymlink' symlink := 'tsymlink'
os.rm(symlink) os.rm(symlink) or { }
os.rm(folder) os.rm(folder) or { }
os.mkdir(folder) or { panic(err) } os.mkdir(folder) or { panic(err) }
folder_contents := os.ls(folder) or { panic(err) } folder_contents := os.ls(folder) or { panic(err) }
assert folder_contents.len == 0 assert folder_contents.len == 0
os.system('ln -s $folder $symlink') os.system('ln -s $folder $symlink')
assert os.is_link(symlink) == true assert os.is_link(symlink) == true
os.rm(symlink) os.rm(symlink) or { panic(err) }
os.rm(folder) os.rm(folder) or { panic(err) }
folder_exists := os.is_dir(folder) folder_exists := os.is_dir(folder)
assert folder_exists == false assert folder_exists == false
symlink_exists := os.is_link(symlink) symlink_exists := os.is_link(symlink)
@ -343,8 +343,8 @@ fn test_symlink() {
os.symlink('symlink', 'symlink2') or { panic(err) } os.symlink('symlink', 'symlink2') or { panic(err) }
assert os.exists('symlink2') assert os.exists('symlink2')
// cleanup // cleanup
os.rm('symlink') os.rm('symlink') or { panic(err) }
os.rm('symlink2') os.rm('symlink2') or { panic(err) }
} }
fn test_is_executable_writable_readable() { fn test_is_executable_writable_readable() {
@ -367,7 +367,7 @@ fn test_is_executable_writable_readable() {
assert os.is_executable(file_name) assert os.is_executable(file_name)
} }
// We finally delete the test file. // We finally delete the test file.
os.rm(file_name) os.rm(file_name) or { panic(err) }
} }
fn test_ext() { fn test_ext() {
@ -438,7 +438,7 @@ fn test_write_file_array_bytes() {
for i in 0 .. maxn { for i in 0 .. maxn {
arr[i] = 65 + byte(i) arr[i] = 65 + byte(i)
} }
os.write_file_array(fpath, arr) os.write_file_array(fpath, arr) or { panic(err) }
rarr := os.read_bytes(fpath) or { panic(err) } rarr := os.read_bytes(fpath) or { panic(err) }
assert arr == rarr assert arr == rarr
// eprintln(arr.str()) // eprintln(arr.str())
@ -451,7 +451,7 @@ fn test_write_file_array_structs() {
for i in 0 .. maxn { for i in 0 .. maxn {
arr[i] = IntPoint{65 + i, 65 + i + 10} arr[i] = IntPoint{65 + i, 65 + i + 10}
} }
os.write_file_array(fpath, arr) os.write_file_array(fpath, arr) or { panic(err) }
rarr := os.read_file_array<IntPoint>(fpath) rarr := os.read_file_array<IntPoint>(fpath)
assert rarr == arr assert rarr == arr
assert rarr.len == maxn assert rarr.len == maxn
@ -519,6 +519,6 @@ fn test_posix_set_bit() {
} }
mode = u32(s.st_mode) & 0o7777 mode = u32(s.st_mode) & 0o7777
assert mode == 0o0755 assert mode == 0o0755
rm(fpath) rm(fpath) or { }
} }
} }

View File

@ -9,9 +9,10 @@ import time
#include <termios.h> #include <termios.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <signal.h> #include <signal.h>
fn C.tcgetattr() fn C.tcgetattr()
fn C.tcsetattr() fn C.tcsetattr()
fn C.ioctl(fd int, request u64, arg voidptr) int fn C.ioctl(fd int, request u64, arg voidptr) int
struct C.termios { struct C.termios {
@ -103,7 +104,6 @@ fn (mut ctx Context) termios_setup() ? {
// feature-test rgb (truecolor) support // feature-test rgb (truecolor) support
ctx.enable_rgb = supports_truecolor() ctx.enable_rgb = supports_truecolor()
} }
// Prevent stdin from blocking by making its read time 0 // Prevent stdin from blocking by making its read time 0
termios.c_cc[C.VTIME] = 0 termios.c_cc[C.VTIME] = 0
termios.c_cc[C.VMIN] = 0 termios.c_cc[C.VMIN] = 0
@ -124,7 +124,7 @@ fn (mut ctx Context) termios_setup() ? {
os.signal(C.SIGCONT, fn () { os.signal(C.SIGCONT, fn () {
mut c := ctx_ptr mut c := ctx_ptr
if c != 0 { if c != 0 {
c.termios_setup() c.termios_setup() or { panic(err) }
c.window_height, c.window_width = get_terminal_size() c.window_height, c.window_width = get_terminal_size()
mut event := &Event{ mut event := &Event{
typ: .resized typ: .resized
@ -136,7 +136,7 @@ fn (mut ctx Context) termios_setup() ? {
} }
}) })
for code in ctx.cfg.reset { for code in ctx.cfg.reset {
os.signal(code, fn() { os.signal(code, fn () {
mut c := ctx_ptr mut c := ctx_ptr
if c != 0 { if c != 0 {
c.cleanup() c.cleanup()
@ -145,7 +145,7 @@ fn (mut ctx Context) termios_setup() ? {
}) })
} }
os.signal(C.SIGWINCH, fn() { os.signal(C.SIGWINCH, fn () {
mut c := ctx_ptr mut c := ctx_ptr
if c != 0 { if c != 0 {
c.window_height, c.window_width = get_terminal_size() c.window_height, c.window_width = get_terminal_size()
@ -166,10 +166,14 @@ fn get_cursor_position() (int, int) {
print('\033[6n') print('\033[6n')
buf := malloc(25) buf := malloc(25)
len := C.read(C.STDIN_FILENO, buf, 24) len := C.read(C.STDIN_FILENO, buf, 24)
unsafe { buf[len] = 0 } unsafe {
buf[len] = 0
}
s := tos(buf, len) s := tos(buf, len)
a := s[2..].split(';') a := s[2..].split(';')
if a.len != 2 { return -1, -1 } if a.len != 2 {
return -1, -1
}
return a[0].int(), a[1].int() return a[0].int(), a[1].int()
} }
@ -184,14 +188,16 @@ fn supports_truecolor() bool {
print('\x1bP\$qm\x1b\\') print('\x1bP\$qm\x1b\\')
buf := malloc(25) buf := malloc(25)
len := C.read(C.STDIN_FILENO, buf, 24) len := C.read(C.STDIN_FILENO, buf, 24)
unsafe { buf[len] = 0 } unsafe {
buf[len] = 0
}
s := tos(buf, len) s := tos(buf, len)
return '1:2:3' in s return '1:2:3' in s
} }
fn termios_reset() { fn termios_reset() {
C.tcsetattr(C.STDIN_FILENO, C.TCSAFLUSH /* C.TCSANOW ?? */, &termios_at_startup) // C.TCSANOW ??
C.tcsetattr(C.STDIN_FILENO, C.TCSAFLUSH, &ui.termios_at_startup)
print('\x1b[?1003l\x1b[?1006l\x1b[?25h') print('\x1b[?1003l\x1b[?1006l\x1b[?25h')
c := ctx_ptr c := ctx_ptr
if c != 0 && c.cfg.use_alternate_buffer { if c != 0 && c.cfg.use_alternate_buffer {
@ -201,7 +207,6 @@ fn termios_reset() {
} }
/////////////////////////////////////////// ///////////////////////////////////////////
// TODO: do multiple sleep/read cycles, rather than one big one // TODO: do multiple sleep/read cycles, rather than one big one
fn (mut ctx Context) termios_loop() { fn (mut ctx Context) termios_loop() {
frame_time := 1_000_000 / ctx.cfg.frame_rate frame_time := 1_000_000 / ctx.cfg.frame_rate
@ -221,7 +226,8 @@ fn (mut ctx Context) termios_loop() {
sw.restart() sw.restart()
if ctx.cfg.event_fn != voidptr(0) { if ctx.cfg.event_fn != voidptr(0) {
unsafe { unsafe {
len := C.read(C.STDIN_FILENO, byteptr(ctx.read_buf.data) + ctx.read_buf.len, ctx.read_buf.cap - ctx.read_buf.len) len := C.read(C.STDIN_FILENO, byteptr(ctx.read_buf.data) + ctx.read_buf.len,
ctx.read_buf.cap - ctx.read_buf.len)
ctx.resize_arr(ctx.read_buf.len + len) ctx.resize_arr(ctx.read_buf.len + len)
} }
if ctx.read_buf.len > 0 { if ctx.read_buf.len > 0 {
@ -243,7 +249,9 @@ fn (mut ctx Context) parse_events() {
mut nr_iters := 0 mut nr_iters := 0
for ctx.read_buf.len > 0 { for ctx.read_buf.len > 0 {
nr_iters++ nr_iters++
if nr_iters > 100 { ctx.shift(1) } if nr_iters > 100 {
ctx.shift(1)
}
mut event := &Event(0) mut event := &Event(0)
if ctx.read_buf[0] == 0x1b { if ctx.read_buf[0] == 0x1b {
e, len := escape_sequence(ctx.read_buf.bytestr()) e, len := escape_sequence(ctx.read_buf.bytestr())
@ -272,41 +280,52 @@ fn single_char(buf string) &Event {
match ch { match ch {
// special handling for `ctrl + letter` // special handling for `ctrl + letter`
// TODO: Fix assoc in V and remove this workaround :/ // TODO: Fix assoc in V and remove this workaround :/
// 1 ... 26 { event = Event{ ...event, code: KeyCode(96 | ch), modifiers: ctrl } } // 1 ... 26 { event = Event{ ...event, code: KeyCode(96 | ch), modifiers: ctrl } }
// 65 ... 90 { event = Event{ ...event, code: KeyCode(32 | ch), modifiers: shift } } // 65 ... 90 { event = Event{ ...event, code: KeyCode(32 | ch), modifiers: shift } }
// The bit `or`s here are really just `+`'s, just written in this way for a tiny performance improvement // The bit `or`s here are really just `+`'s, just written in this way for a tiny performance improvement
// don't treat tab, enter as ctrl+i, ctrl+j // don't treat tab, enter as ctrl+i, ctrl+j
1 ... 8, 11 ... 26 { event = &Event{ typ: event.typ, ascii: event.ascii, utf8: event.utf8, code: KeyCode(96 | ch), modifiers: ctrl } } 1...8, 11...26 { event = &Event{
65 ... 90 { event = &Event{ typ: event.typ, ascii: event.ascii, utf8: event.utf8, code: KeyCode(32 | ch), modifiers: shift } } typ: event.typ
ascii: event.ascii
utf8: event.utf8
code: KeyCode(96 | ch)
modifiers: ctrl
} }
65...90 { event = &Event{
typ: event.typ
ascii: event.ascii
utf8: event.utf8
code: KeyCode(32 | ch)
modifiers: shift
} }
else {} else {}
} }
return event return event
} }
[inline]
// Gets an entire, independent escape sequence from the buffer // Gets an entire, independent escape sequence from the buffer
// Normally, this just means reading until the first letter, but there are some exceptions... // Normally, this just means reading until the first letter, but there are some exceptions...
fn escape_end(buf string) int { fn escape_end(buf string) int {
mut i := 0 mut i := 0
for { for {
if i + 1 == buf.len { return buf.len } if i + 1 == buf.len {
return buf.len
}
if buf[i].is_letter() || buf[i] == `~` { if buf[i].is_letter() || buf[i] == `~` {
if buf[i] == `O` && i + 2 <= buf.len { if buf[i] == `O` && i + 2 <= buf.len {
n := buf[i+1] n := buf[i + 1]
if (n >= `A` && n <= `D`) || (n >= `P` && n <= `S`) || n == `F` || n == `H` { if (n >= `A` && n <= `D`) || (n >= `P` && n <= `S`) || n == `F` || n == `H` {
return i + 2 return i + 2
} }
} }
return i + 1 return i + 1
// escape hatch to avoid potential issues/crashes, although ideally this should never eval to true // escape hatch to avoid potential issues/crashes, although ideally this should never eval to true
} else if buf[i + 1] == 0x1b { return i + 1 } } else if buf[i + 1] == 0x1b {
return i + 1
}
i++ i++
} }
// this point should be unreachable // this point should be unreachable
@ -339,51 +358,85 @@ fn escape_sequence(buf_ string) (&Event, int) {
modifiers: c.modifiers | alt modifiers: c.modifiers | alt
}, 2 }, 2
} }
// ---------------- // ----------------
// Mouse events // Mouse events
// ---------------- // ----------------
// Documentation: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking // Documentation: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
if buf.len > 2 && buf[1] == `<` { if buf.len > 2 && buf[1] == `<` {
split := buf[2..].split(';') split := buf[2..].split(';')
if split.len < 3 { return &Event(0), 0 } if split.len < 3 {
return &Event(0), 0
}
typ, x, y := split[0].int(), split[1].int(), split[2].int() typ, x, y := split[0].int(), split[1].int(), split[2].int()
lo := typ & 0b00011 lo := typ & 0b00011
hi := typ & 0b11100 hi := typ & 0b11100
mut modifiers := u32(0) mut modifiers := u32(0)
if hi & 4 != 0 { modifiers |= shift } if hi & 4 != 0 {
if hi & 8 != 0 { modifiers |= alt } modifiers |= shift
if hi & 16 != 0 { modifiers |= ctrl } }
if hi & 8 != 0 {
modifiers |= alt
}
if hi & 16 != 0 {
modifiers |= ctrl
}
match typ { match typ {
0...31 { 0...31 {
last := buf[buf.len - 1] last := buf[buf.len - 1]
button := if lo < 3 { MouseButton(lo + 1) } else { MouseButton.unknown } button := if lo < 3 { MouseButton(lo + 1) } else { MouseButton.unknown }
event := if last == `m` || lo == 3 { EventType.mouse_up } else { EventType.mouse_down } event := if last == `m` || lo == 3 {
EventType.mouse_up
} else {
EventType.mouse_down
}
return &Event{ typ: event, x: x, y: y, button: button, modifiers: modifiers utf8: single }, end return &Event{
typ: event
x: x
y: y
button: button
modifiers: modifiers
utf8: single
}, end
} }
32...63 { 32...63 {
button, event := if lo < 3 { button, event := if lo < 3 {
MouseButton(lo + 1), EventType.mouse_drag MouseButton(lo + 1), EventType.mouse_drag
} else { } else {
MouseButton.unknown, EventType.mouse_move MouseButton.unknown, EventType.mouse_move
} }
return &Event{ typ: event, x: x, y: y, button: button, modifiers: modifiers, utf8: single }, end return &Event{
typ: event
x: x
y: y
button: button
modifiers: modifiers
utf8: single
}, end
} }
64...95 { 64...95 {
direction := if typ & 1 == 0 { Direction.down } else { Direction.up } direction := if typ & 1 == 0 { Direction.down } else { Direction.up }
return &Event{ typ: .mouse_scroll, x: x, y: y, direction: direction, modifiers: modifiers, utf8: single }, end return &Event{
} else { typ: .mouse_scroll
return &Event{ typ: .unknown, utf8: single }, end x: x
y: y
direction: direction
modifiers: modifiers
utf8: single
}, end
}
else {
return &Event{
typ: .unknown
utf8: single
}, end
} }
} }
} }
// ---------------------------- // ----------------------------
// Special key combinations // Special key combinations
// ---------------------------- // ----------------------------
@ -391,29 +444,29 @@ fn escape_sequence(buf_ string) (&Event, int) {
mut code := KeyCode.null mut code := KeyCode.null
mut modifiers := u32(0) mut modifiers := u32(0)
match buf { match buf {
'[A', 'OA' { code = .up } '[A', 'OA' { code = .up }
'[B', 'OB' { code = .down } '[B', 'OB' { code = .down }
'[C', 'OC' { code = .right } '[C', 'OC' { code = .right }
'[D', 'OD' { code = .left } '[D', 'OD' { code = .left }
'[5~', '[[5~' { code = .page_up } '[5~', '[[5~' { code = .page_up }
'[6~', '[[6~' { code = .page_down } '[6~', '[[6~' { code = .page_down }
'[F', 'OF', '[4~', '[[8~' { code = .end } '[F', 'OF', '[4~', '[[8~' { code = .end }
'[H', 'OH', '[1~', '[[7~' { code = .home } '[H', 'OH', '[1~', '[[7~' { code = .home }
'[2~' { code = .insert } '[2~' { code = .insert }
'[3~' { code = .delete } '[3~' { code = .delete }
'OP', '[11~' { code = .f1 } 'OP', '[11~' { code = .f1 }
'OQ', '[12~' { code = .f2 } 'OQ', '[12~' { code = .f2 }
'OR', '[13~' { code = .f3 } 'OR', '[13~' { code = .f3 }
'OS', '[14~' { code = .f4 } 'OS', '[14~' { code = .f4 }
'[15~' { code = .f5 } '[15~' { code = .f5 }
'[17~' { code = .f6 } '[17~' { code = .f6 }
'[18~' { code = .f7 } '[18~' { code = .f7 }
'[19~' { code = .f8 } '[19~' { code = .f8 }
'[20~' { code = .f9 } '[20~' { code = .f9 }
'[21~' { code = .f10 } '[21~' { code = .f10 }
'[23~' { code = .f11 } '[23~' { code = .f11 }
'[24~' { code = .f12 } '[24~' { code = .f12 }
else {} else {}
} }
if buf == '[Z' { if buf == '[Z' {
@ -455,5 +508,10 @@ fn escape_sequence(buf_ string) (&Event, int) {
} }
} }
return &Event{ typ: .key_down, code: code, utf8: single, modifiers: modifiers }, end return &Event{
typ: .key_down
code: code
utf8: single
modifiers: modifiers
}, end
} }

View File

@ -35,7 +35,7 @@ pub fn (mut b Builder) build_c(v_files []string, out_file string) {
b.info('build_c($out_file)') b.info('build_c($out_file)')
output2 := b.gen_c(v_files) output2 := b.gen_c(v_files)
mut f := os.create(out_file) or { panic(err) } mut f := os.create(out_file) or { panic(err) }
f.writeln(output2) f.writeln(output2) or { panic(err) }
f.close() f.close()
// os.write_file(out_file, b.gen_c(v_files)) // os.write_file(out_file, b.gen_c(v_files))
} }
@ -75,9 +75,9 @@ pub fn (mut b Builder) compile_c() {
bundle_name := b.pref.out_name.split('/').last() bundle_name := b.pref.out_name.split('/').last()
bundle_id := if b.pref.bundle_id != '' { b.pref.bundle_id } else { 'app.vlang.$bundle_name' } bundle_id := if b.pref.bundle_id != '' { b.pref.bundle_id } else { 'app.vlang.$bundle_name' }
display_name := if b.pref.display_name != '' { b.pref.display_name } else { bundle_name } display_name := if b.pref.display_name != '' { b.pref.display_name } else { bundle_name }
os.mkdir('${display_name}.app') os.mkdir('${display_name}.app') or { panic(err) }
os.write_file('${display_name}.app/Info.plist', make_ios_plist(display_name, bundle_id, os.write_file('${display_name}.app/Info.plist', make_ios_plist(display_name, bundle_id,
bundle_name, 1)) bundle_name, 1)) or { panic(err) }
} }
b.cc() b.cc()
} }

View File

@ -92,7 +92,7 @@ fn (mut v Builder) post_process_c_compiler_output(res os.Result) {
if v.pref.is_verbose { if v.pref.is_verbose {
eprintln('>> remove tmp file: $tmpfile') eprintln('>> remove tmp file: $tmpfile')
} }
os.rm(tmpfile) os.rm(tmpfile) or { panic(err) }
} }
} }
return return
@ -414,7 +414,9 @@ fn (mut v Builder) setup_output_name() {
if v.pref.is_verbose { if v.pref.is_verbose {
println('Building $v.pref.path to $v.pref.out_name ...') println('Building $v.pref.path to $v.pref.out_name ...')
} }
v.pref.cache_manager.save('.description.txt', v.pref.path, '${v.pref.path:-30} @ $v.pref.cache_manager.vopts\n') v.pref.cache_manager.save('.description.txt', v.pref.path, '${v.pref.path:-30} @ $v.pref.cache_manager.vopts\n') or {
panic(err)
}
// println('v.table.imports:') // println('v.table.imports:')
// println(v.table.imports) // println(v.table.imports)
} }
@ -734,7 +736,7 @@ fn (mut b Builder) cc_linux_cross() {
b.setup_output_name() b.setup_output_name()
parent_dir := os.vmodules_dir() parent_dir := os.vmodules_dir()
if !os.exists(parent_dir) { if !os.exists(parent_dir) {
os.mkdir(parent_dir) os.mkdir(parent_dir) or { panic(err) }
} }
sysroot := os.join_path(os.vmodules_dir(), 'linuxroot') sysroot := os.join_path(os.vmodules_dir(), 'linuxroot')
if !os.is_dir(sysroot) { if !os.is_dir(sysroot) {
@ -917,7 +919,7 @@ fn (mut v Builder) build_thirdparty_obj_file(path string, moduleflags []cflag.CF
// for example thirdparty\tcc\lib\openlibm.o // for example thirdparty\tcc\lib\openlibm.o
// the best we can do for them is just copy them, // the best we can do for them is just copy them,
// and hope that they work with any compiler... // and hope that they work with any compiler...
os.cp(obj_path, opath) os.cp(obj_path, opath) or { panic(err) }
return return
} }
println('$obj_path not found, building it in $opath ...') println('$obj_path not found, building it in $opath ...')
@ -943,7 +945,9 @@ fn (mut v Builder) build_thirdparty_obj_file(path string, moduleflags []cflag.CF
verror(res.output) verror(res.output)
return return
} }
v.pref.cache_manager.save('.description.txt', obj_path, '${obj_path:-30} @ $cmd\n') v.pref.cache_manager.save('.description.txt', obj_path, '${obj_path:-30} @ $cmd\n') or {
panic(err)
}
println(res.output) println(res.output)
} }

View File

@ -93,12 +93,12 @@ fn (mut b Builder) run_compiled_executable_and_exit() {
} }
if b.pref.os == .ios { if b.pref.os == .ios {
device := '"iPhone SE (2nd generation)"' device := '"iPhone SE (2nd generation)"'
os.exec('xcrun simctl boot $device') os.exec('xcrun simctl boot $device') or { panic(err) }
bundle_name := b.pref.out_name.split('/').last() bundle_name := b.pref.out_name.split('/').last()
display_name := if b.pref.display_name != '' { b.pref.display_name } else { bundle_name } display_name := if b.pref.display_name != '' { b.pref.display_name } else { bundle_name }
os.exec('xcrun simctl install $device ${display_name}.app') os.exec('xcrun simctl install $device ${display_name}.app') or { panic(err) }
bundle_id := if b.pref.bundle_id != '' { b.pref.bundle_id } else { 'app.vlang.$bundle_name' } bundle_id := if b.pref.bundle_id != '' { b.pref.bundle_id } else { 'app.vlang.$bundle_name' }
os.exec('xcrun simctl launch $device $bundle_id') os.exec('xcrun simctl launch $device $bundle_id') or { panic(err) }
} else { } else {
exefile := os.real_path(b.pref.out_name) exefile := os.real_path(b.pref.out_name)
mut cmd := '"$exefile"' mut cmd := '"$exefile"'
@ -133,7 +133,7 @@ fn (mut v Builder) cleanup_run_executable_after_exit(exefile string) {
} }
if os.is_file(exefile) { if os.is_file(exefile) {
v.pref.vrun_elog('remove run executable: $exefile') v.pref.vrun_elog('remove run executable: $exefile')
os.rm(exefile) os.rm(exefile) or { panic(err) }
} }
} }

View File

@ -29,7 +29,7 @@ pub fn (mut b Builder) build_js(v_files []string, out_file string) {
b.info('build_js($out_file)') b.info('build_js($out_file)')
output := b.gen_js(v_files) output := b.gen_js(v_files)
mut f := os.create(out_file) or { panic(err) } mut f := os.create(out_file) or { panic(err) }
f.writeln(output) f.writeln(output) or { panic(err) }
f.close() f.close()
} }

View File

@ -315,7 +315,7 @@ pub fn (mut v Builder) cc_msvc() {
// println(res) // println(res)
// println('C OUTPUT:') // println('C OUTPUT:')
// Always remove the object file - it is completely unnecessary // Always remove the object file - it is completely unnecessary
os.rm(out_name_obj) os.rm(out_name_obj) or { panic(err) }
} }
fn (mut v Builder) build_thirdparty_obj_file_with_msvc(path string, moduleflags []cflag.CFlag) { fn (mut v Builder) build_thirdparty_obj_file_with_msvc(path string, moduleflags []cflag.CFlag) {

View File

@ -1930,10 +1930,8 @@ pub fn (mut c Checker) check_expr_opt_call(expr ast.Expr, ret_type table.Type) t
if expr is ast.CallExpr { if expr is ast.CallExpr {
if expr.return_type.has_flag(.optional) { if expr.return_type.has_flag(.optional) {
if expr.or_block.kind == .absent { if expr.or_block.kind == .absent {
if ret_type != table.void_type { c.error('${expr.name}() returns an option, so it should have either an `or {}` block, or `?` at the end',
c.error('${expr.name}() returns an option but is missing an `or {}` block', expr.pos)
expr.pos)
}
} else { } else {
c.check_or_expr(expr.or_block, ret_type, expr.return_type.clear_flag(.optional)) c.check_or_expr(expr.or_block, ret_type, expr.return_type.clear_flag(.optional))
} }

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/optional_method_err.vv:17:10: error: inc_to_limit() returns an option but is missing an `or {}` block vlib/v/checker/tests/optional_method_err.vv:17:10: error: inc_to_limit() returns an option, so it should have either an `or {}` block, or `?` at the end
15 | mut a := Abc{} 15 | mut a := Abc{}
16 | for _ in 0 .. 4 { 16 | for _ in 0 .. 4 {
17 | _ := a.inc_to_limit(2) 17 | _ := a.inc_to_limit(2)

View File

@ -0,0 +1,6 @@
vlib/v/checker/tests/optional_void_called_as_normal.vv:7:2: error: foo() returns an option, so it should have either an `or {}` block, or `?` at the end
5 | fn main() {
6 | // Calling foo() without ? or an or block, should be an error.
7 | foo()
| ~~~~~
8 | }

View File

@ -0,0 +1,8 @@
fn foo() ? {
println('foo is called')
}
fn main() {
// Calling foo() without ? or an or block, should be an error.
foo()
}

View File

@ -13,7 +13,7 @@ const skip_files = [
const skip_on_ubuntu_musl = [ const skip_on_ubuntu_musl = [
'vlib/v/checker/tests/vweb_tmpl_used_var.vv', 'vlib/v/checker/tests/vweb_tmpl_used_var.vv',
] ]
const turn_off_vcolors = os.setenv('VCOLORS', 'never', true) const turn_off_vcolors = os.setenv('VCOLORS', 'never', true)
@ -179,7 +179,7 @@ fn (mut task TaskDescription) execute() {
res := os.exec(cli_cmd) or { panic(err) } res := os.exec(cli_cmd) or { panic(err) }
expected_out_path := program.replace('.vv', '') + task.result_extension expected_out_path := program.replace('.vv', '') + task.result_extension
if should_autofix && !os.exists(expected_out_path) { if should_autofix && !os.exists(expected_out_path) {
os.write_file(expected_out_path, '') os.write_file(expected_out_path, '') or { panic(err) }
} }
mut expected := os.read_file(expected_out_path) or { panic(err) } mut expected := os.read_file(expected_out_path) or { panic(err) }
task.expected = clean_line_endings(expected) task.expected = clean_line_endings(expected)
@ -192,7 +192,7 @@ fn (mut task TaskDescription) execute() {
if task.expected != task.found___ { if task.expected != task.found___ {
task.is_error = true task.is_error = true
if should_autofix { if should_autofix {
os.write_file(expected_out_path, res.output) os.write_file(expected_out_path, res.output) or { panic(err) }
} }
} }
} }

View File

@ -67,7 +67,7 @@ fn test_fmt() {
continue continue
} }
vfmt_result_file := os.join_path(tmpfolder, 'vfmt_run_over_$ifilename') vfmt_result_file := os.join_path(tmpfolder, 'vfmt_run_over_$ifilename')
os.write_file(vfmt_result_file, result_ocontent) os.write_file(vfmt_result_file, result_ocontent) or { panic(err) }
eprintln(util.color_compare_files(diff_cmd, opath, vfmt_result_file)) eprintln(util.color_compare_files(diff_cmd, opath, vfmt_result_file))
continue continue
} }

View File

@ -58,7 +58,7 @@ fn test_fmt() {
continue continue
} }
vfmt_result_file := os.join_path(tmpfolder, 'vfmt_run_over_$ifilename') vfmt_result_file := os.join_path(tmpfolder, 'vfmt_run_over_$ifilename')
os.write_file(vfmt_result_file, result_ocontent) os.write_file(vfmt_result_file, result_ocontent) or { panic(err) }
eprintln(util.color_compare_files(diff_cmd, opath, vfmt_result_file)) eprintln(util.color_compare_files(diff_cmd, opath, vfmt_result_file))
continue continue
} }

View File

@ -56,7 +56,7 @@ fn test_vlib_fmt() {
continue continue
} }
vfmt_result_file := os.join_path(tmpfolder, 'vfmt_run_over_$ifilename') vfmt_result_file := os.join_path(tmpfolder, 'vfmt_run_over_$ifilename')
os.write_file(vfmt_result_file, result_ocontent) os.write_file(vfmt_result_file, result_ocontent) or { panic(err) }
eprintln(util.color_compare_files(diff_cmd, opath, vfmt_result_file)) eprintln(util.color_compare_files(diff_cmd, opath, vfmt_result_file))
continue continue
} }

View File

@ -7,7 +7,7 @@ const (
) )
fn testsuite_end() { fn testsuite_end() {
os.rmdir_all(main.output_dir) os.rmdir_all(output_dir) or { }
} }
const there_is_node_available = is_nodejs_working() const there_is_node_available = is_nodejs_working()
@ -15,22 +15,22 @@ const there_is_node_available = is_nodejs_working()
fn test_example_compilation() { fn test_example_compilation() {
vexe := os.getenv('VEXE') vexe := os.getenv('VEXE')
os.chdir(os.dir(vexe)) os.chdir(os.dir(vexe))
os.mkdir_all(main.output_dir) os.mkdir_all(output_dir) or { panic(err) }
files := find_test_files() files := find_test_files()
for file in files { for file in files {
path := os.join_path(main.test_dir, file) path := os.join_path(test_dir, file)
println('Testing $file') println('Testing $file')
v_code := os.system('$vexe $main.v_options -o $main.output_dir${file}.js $path') v_code := os.system('$vexe $v_options -o $output_dir${file}.js $path')
if v_code != 0 { if v_code != 0 {
assert false assert false
} }
// Compilation failed // Compilation failed
assert v_code == 0 assert v_code == 0
if !main.there_is_node_available { if !there_is_node_available {
println(' ... skipping running $file, there is no NodeJS present') println(' ... skipping running $file, there is no NodeJS present')
continue continue
} }
js_code := os.system('node $main.output_dir${file}.js') js_code := os.system('node $output_dir${file}.js')
if js_code != 0 { if js_code != 0 {
assert false assert false
} }
@ -40,7 +40,7 @@ fn test_example_compilation() {
} }
fn find_test_files() []string { fn find_test_files() []string {
files := os.ls(main.test_dir) or { panic(err) } files := os.ls(test_dir) or { panic(err) }
// The life example never exits, so tests would hang with it, skip // The life example never exits, so tests would hang with it, skip
mut tests := files.filter(it.ends_with('.v')).filter(it != 'life.v') mut tests := files.filter(it.ends_with('.v')).filter(it != 'life.v')
tests.sort() tests.sort()

View File

@ -15,12 +15,10 @@ fn test_x64() {
vexe := os.getenv('VEXE') vexe := os.getenv('VEXE')
vroot := os.dir(vexe) vroot := os.dir(vexe)
dir := os.join_path(vroot, 'vlib/v/gen/x64/tests') dir := os.join_path(vroot, 'vlib/v/gen/x64/tests')
files := os.ls(dir) or { files := os.ls(dir) or { panic(err) }
panic(err)
}
// //
wrkdir := os.join_path(os.temp_dir(), 'vtests', 'x64') wrkdir := os.join_path(os.temp_dir(), 'vtests', 'x64')
os.mkdir_all(wrkdir) os.mkdir_all(wrkdir) or { panic(err) }
os.chdir(wrkdir) os.chdir(wrkdir)
tests := files.filter(it.ends_with('.vv')) tests := files.filter(it.ends_with('.vv'))
if tests.len == 0 { if tests.len == 0 {
@ -48,9 +46,7 @@ fn test_x64() {
eprintln(res.output) eprintln(res.output)
continue continue
} }
mut expected := os.read_file('$dir/${test}.out') or { mut expected := os.read_file('$dir/${test}.out') or { panic(err) }
panic(err)
}
expected = expected.trim_right('\r\n').replace('\r\n', '\n') expected = expected.trim_right('\r\n').replace('\r\n', '\n')
mut found := res.output.trim_right('\r\n').replace('\r\n', '\n') mut found := res.output.trim_right('\r\n').replace('\r\n', '\n')
found = found.trim_space() found = found.trim_space()

View File

@ -127,7 +127,7 @@ fn protected_load_lib(mut r live.LiveReloadInfo, new_lib_path string) {
elog(r, '> load_lib OK, new live_lib: $r.live_lib') elog(r, '> load_lib OK, new live_lib: $r.live_lib')
// removing the .so file from the filesystem after dlopen-ing // removing the .so file from the filesystem after dlopen-ing
// it is safe, since it will still be mapped in memory // it is safe, since it will still be mapped in memory
os.rm(new_lib_path) os.rm(new_lib_path) or { }
} }
// NB: r.reloader() is executed in a new, independent thread // NB: r.reloader() is executed in a new, independent thread

View File

@ -60,8 +60,8 @@ fn atomic_write_source(source string) {
// NB: here wrtiting is done in 2 steps, since os.write_file can take some time, // NB: here wrtiting is done in 2 steps, since os.write_file can take some time,
// during which the file will be modified, but it will still be not completely written. // during which the file will be modified, but it will still be not completely written.
// The os.mv after that, guarantees that the reloader will see a complete valid V program. // The os.mv after that, guarantees that the reloader will see a complete valid V program.
os.write_file(tmp_file, source) os.write_file(tmp_file, source) or { panic(err) }
os.mv(tmp_file, source_file) os.mv(tmp_file, source_file) or { panic(err) }
} }
// //
@ -75,7 +75,7 @@ fn testsuite_begin() {
for f in [tmp_file, source_file, output_file, res_original_file, res_changed_file, res_another_file, for f in [tmp_file, source_file, output_file, res_original_file, res_changed_file, res_another_file,
res_stop_file, res_stop_file,
] { ] {
os.rm(f) os.rm(f) or { }
} }
atomic_write_source(live_program_source) atomic_write_source(live_program_source)
} }
@ -105,7 +105,7 @@ fn testsuite_end() {
assert histogram['CHANGED'] + histogram['ANOTHER'] > 0 assert histogram['CHANGED'] + histogram['ANOTHER'] > 0
// assert histogram['END'] > 0 // assert histogram['END'] > 0
for tfile in cleanup_files { for tfile in cleanup_files {
os.rm(tfile) os.rm(tfile) or { }
} }
} }

View File

@ -9,9 +9,12 @@ fn append_to_file(fname string, s string) {
println('>>>> could not open file $fname for appending, err: $err ') println('>>>> could not open file $fname for appending, err: $err ')
return return
} }
f.writeln(s) f.writeln(s) or {
//info := live.info() println('>>>> could not write to $fname, err: $err ')
//f.writeln('>>> reloads: ${info.reloads} | ok reloads: ${info.reloads_ok}') return
}
// info := live.info()
// f.writeln('>>> reloads: ${info.reloads} | ok reloads: ${info.reloads_ok}')
f.close() f.close()
} }
@ -29,6 +32,7 @@ fn pmessage() string {
const ( const (
delay = 20 delay = 20
) )
fn edefault(name string, default string) string { fn edefault(name string, default string) string {
res := os.getenv(name) res := os.getenv(name)
if res == '' { if res == '' {
@ -36,6 +40,7 @@ fn edefault(name string, default string) string {
} }
return res return res
} }
fn main() { fn main() {
mut info := live.info() mut info := live.info()
info.recheck_period_ms = 5 info.recheck_period_ms = 5
@ -45,7 +50,7 @@ fn main() {
pmessage() pmessage()
max_cycles := edefault('LIVE_CYCLES', '1').int() max_cycles := edefault('LIVE_CYCLES', '1').int()
// NB: 1000 * 20 = maximum of ~20s runtime // NB: 1000 * 20 = maximum of ~20s runtime
for i:=0; i<max_cycles; i++ { for i := 0; i < max_cycles; i++ {
s := pmessage() s := pmessage()
myprintln(s) myprintln(s)
append_to_file(os.resource_abs_path(s + '.txt'), s) append_to_file(os.resource_abs_path(s + '.txt'), s)

View File

@ -112,7 +112,10 @@ fn (mut p Parser) partial_assign_stmt(left []ast.Expr, left_comments []ast.Comme
if op == .decl_assign { if op == .decl_assign {
// a, b := a + 1, b // a, b := a + 1, b
for r in right { for r in right {
p.check_undefined_variables(left, r) p.check_undefined_variables(left, r) or {
p.error('check_undefined_variables failed')
return ast.Stmt{}
}
} }
} else if left.len > 1 { } else if left.len > 1 {
// a, b = b, a // a, b = b, a

View File

@ -94,7 +94,7 @@ pub fn (mut m Main) run() ?string {
res += pcdep.description res += pcdep.description
} }
if pc != 0 { if pc != 0 {
pc.extend(pcdep) pc.extend(pcdep) ?
} else { } else {
pc = pcdep pc = pcdep
} }

View File

@ -155,7 +155,7 @@ fn (mut pc PkgConfig) resolve(pkgname string) ?string {
} }
pub fn atleast(v string) bool { pub fn atleast(v string) bool {
v0 := semver.from(version) or { return false } v0 := semver.from(pkgconfig.version) or { return false }
v1 := semver.from(v) or { return false } v1 := semver.from(v) or { return false }
return v0.gt(v1) return v0.gt(v1)
} }
@ -207,8 +207,8 @@ fn (mut pc PkgConfig) load_require(dep string) ? {
if !pcdep.parse(depfile) { if !pcdep.parse(depfile) {
return error('required file "$depfile" could not be parsed') return error('required file "$depfile" could not be parsed')
} }
pcdep.load_requires() or { return error(err) } pcdep.load_requires() ?
pc.extend(pcdep) pc.extend(pcdep) ?
} }
fn (mut pc PkgConfig) add_path(path string) { fn (mut pc PkgConfig) add_path(path string) {
@ -223,7 +223,7 @@ fn (mut pc PkgConfig) add_path(path string) {
fn (mut pc PkgConfig) load_paths() { fn (mut pc PkgConfig) load_paths() {
if pc.options.use_default_paths { if pc.options.use_default_paths {
for path in default_paths { for path in pkgconfig.default_paths {
pc.add_path(path) pc.add_path(path)
} }
} }

View File

@ -474,10 +474,10 @@ pub fn parse_args(args []string) (&Preferences, string) {
// //
if output_option.len != 0 { if output_option.len != 0 {
res.vrun_elog('remove tmp exe file: $tmp_exe_file_path') res.vrun_elog('remove tmp exe file: $tmp_exe_file_path')
os.rm(tmp_exe_file_path) os.rm(tmp_exe_file_path) or { }
} }
res.vrun_elog('remove tmp v file: $tmp_v_file_path') res.vrun_elog('remove tmp v file: $tmp_v_file_path')
os.rm(tmp_v_file_path) os.rm(tmp_v_file_path) or { panic(err) }
exit(tmp_result) exit(tmp_result)
} }
must_exist(res.path) must_exist(res.path)

View File

@ -33,13 +33,13 @@ fn test_all() {
panic(err) panic(err)
} }
$if windows { $if windows {
os.rm('./test.exe') os.rm('./test.exe') or { }
$if msvc { $if msvc {
os.rm('./test.ilk') os.rm('./test.ilk') or { }
os.rm('./test.pdb') os.rm('./test.pdb') or { }
} }
} $else { } $else {
os.rm('./test') os.rm('./test') or { }
} }
// println('============') // println('============')
// println(res.output) // println(res.output)

View File

@ -64,7 +64,7 @@ fn worker_repl(mut p sync.PoolProcessor, idx int, thread_id int) voidptr {
tls_bench.cstep = idx tls_bench.cstep = idx
tfolder := os.join_path(cdir, 'vrepl_tests_$idx') tfolder := os.join_path(cdir, 'vrepl_tests_$idx')
if os.is_dir(tfolder) { if os.is_dir(tfolder) {
os.rmdir_all(tfolder) os.rmdir_all(tfolder) or { panic(err) }
} }
os.mkdir(tfolder) or { panic(err) } os.mkdir(tfolder) or { panic(err) }
file := p.get_string_item(idx) file := p.get_string_item(idx)
@ -73,14 +73,14 @@ fn worker_repl(mut p sync.PoolProcessor, idx int, thread_id int) voidptr {
fres := runner.run_repl_file(tfolder, session.options.vexec, file) or { fres := runner.run_repl_file(tfolder, session.options.vexec, file) or {
session.bmark.fail() session.bmark.fail()
tls_bench.fail() tls_bench.fail()
os.rmdir_all(tfolder) os.rmdir_all(tfolder) or { panic(err) }
eprintln(tls_bench.step_message_fail(err)) eprintln(tls_bench.step_message_fail(err))
assert false assert false
return sync.no_result return sync.no_result
} }
session.bmark.ok() session.bmark.ok()
tls_bench.ok() tls_bench.ok()
os.rmdir_all(tfolder) os.rmdir_all(tfolder) or { panic(err) }
println(tls_bench.step_message_ok(fres)) println(tls_bench.step_message_ok(fres))
assert true assert true
return sync.no_result return sync.no_result

View File

@ -35,37 +35,34 @@ pub fn full_path_to_v(dirs_in int) string {
} }
fn diff_files(file_result string, file_expected string) string { fn diff_files(file_result string, file_expected string) string {
diffcmd := util.find_working_diff_command() or { diffcmd := util.find_working_diff_command() or { return err }
return err
}
return util.color_compare_files(diffcmd, file_result, file_expected) return util.color_compare_files(diffcmd, file_result, file_expected)
} }
pub fn run_repl_file(wd string, vexec string, file string) ?string { pub fn run_repl_file(wd string, vexec string, file string) ?string {
vexec_folder := os.dir(vexec) + os.path_separator vexec_folder := os.dir(vexec) + os.path_separator
fcontent := os.read_file(file) or { fcontent := os.read_file(file) or { return error('Could not read file $file') }
return error('Could not read file $file')
}
content := fcontent.replace('\r', '') content := fcontent.replace('\r', '')
input := content.all_before('===output===\n') input := content.all_before('===output===\n')
output := content.all_after('===output===\n').trim_right('\n\r') output := content.all_after('===output===\n').trim_right('\n\r')
fname := os.file_name(file) fname := os.file_name(file)
input_temporary_filename := os.real_path(os.join_path(wd, 'input_temporary_filename.txt')) input_temporary_filename := os.real_path(os.join_path(wd, 'input_temporary_filename.txt'))
os.write_file(input_temporary_filename, input) os.write_file(input_temporary_filename, input) or { panic(err) }
os.write_file(os.real_path(os.join_path(wd, 'original.txt')), fcontent) os.write_file(os.real_path(os.join_path(wd, 'original.txt')), fcontent) or { panic(err) }
rcmd := '"$vexec" repl -replfolder "$wd" -replprefix "${fname}." < $input_temporary_filename' rcmd := '"$vexec" repl -replfolder "$wd" -replprefix "${fname}." < $input_temporary_filename'
r := os.exec(rcmd) or { r := os.exec(rcmd) or {
os.rm(input_temporary_filename) os.rm(input_temporary_filename) or { panic(err) }
return error('Could not execute: $rcmd') return error('Could not execute: $rcmd')
} }
os.rm(input_temporary_filename) os.rm(input_temporary_filename) or { panic(err) }
result := r.output.replace('\r', '').replace('>>> ', '').replace('>>>', '').replace('... ', result := r.output.replace('\r', '').replace('>>> ', '').replace('>>>', '').replace('... ',
'').replace(wd + os.path_separator, '').replace(vexec_folder, '').replace('\\', '/').trim_right('\n\r') '').replace(wd + os.path_separator, '').replace(vexec_folder, '').replace('\\',
'/').trim_right('\n\r')
if result != output { if result != output {
file_result := '${file}.result.txt' file_result := '${file}.result.txt'
file_expected := '${file}.expected.txt' file_expected := '${file}.expected.txt'
os.write_file(file_result, result) os.write_file(file_result, result) or { panic(err) }
os.write_file(file_expected, output) os.write_file(file_expected, output) or { panic(err) }
diff := diff_files(file_result, file_expected) diff := diff_files(file_result, file_expected)
return error('Difference found in REPL file: $file return error('Difference found in REPL file: $file
====> Got : ====> Got :
@ -87,16 +84,14 @@ pub fn run_prod_file(wd string, vexec string, file string) ?string {
} }
expected_content := f_expected_content.replace('\r', '') expected_content := f_expected_content.replace('\r', '')
cmd := '"$vexec" -prod run "$file"' cmd := '"$vexec" -prod run "$file"'
r := os.exec(cmd) or { r := os.exec(cmd) or { return error('Could not execute: $cmd') }
return error('Could not execute: $cmd')
}
if r.exit_code != 0 { if r.exit_code != 0 {
return error('$cmd return exit code: $r.exit_code') return error('$cmd return exit code: $r.exit_code')
} }
result := r.output.replace('\r', '') result := r.output.replace('\r', '')
if result != expected_content { if result != expected_content {
file_result := '${file}.result.txt' file_result := '${file}.result.txt'
os.write_file(file_result, result) os.write_file(file_result, result) or { panic(err) }
diff := diff_files(file_result, file_expected) diff := diff_files(file_result, file_expected)
return error('Difference found in test: $file return error('Difference found in test: $file
====> Got : ====> Got :

View File

@ -19,7 +19,7 @@ fn pipe_to_v_run() ? {
// eprintln('>> cmd: $cmd | res: $res') // eprintln('>> cmd: $cmd | res: $res')
assert res.exit_code == 0 assert res.exit_code == 0
assert res.output.replace('\r', '').trim_space().split('\n') == ['4', 'hello'] assert res.output.replace('\r', '').trim_space().split('\n') == ['4', 'hello']
os.rm(tmp_v_file) os.rm(tmp_v_file) or { panic(err) }
assert !os.exists(tmp_v_file) assert !os.exists(tmp_v_file)
} }

View File

@ -53,13 +53,11 @@ fn test_all() {
files := os.ls(dir) or { panic(err) } files := os.ls(dir) or { panic(err) }
// //
wrkdir := os.join_path(os.temp_dir(), 'vtests', 'valgrind') wrkdir := os.join_path(os.temp_dir(), 'vtests', 'valgrind')
os.mkdir_all(wrkdir) os.mkdir_all(wrkdir) or { panic(err) }
os.chdir(wrkdir) os.chdir(wrkdir)
// //
tests := vtest.filter_vtest_only(files.filter(it.ends_with('.v') && !it.ends_with('_test.v')), only_ordinary_v_files := files.filter(it.ends_with('.v') && !it.ends_with('_test.v'))
tests := vtest.filter_vtest_only(only_ordinary_v_files, basepath: valgrind_test_path)
basepath: valgrind_test_path
)
bench.set_total_expected_steps(tests.len) bench.set_total_expected_steps(tests.len)
for test in tests { for test in tests {
bench.step() bench.step()

View File

@ -63,10 +63,10 @@ pub fn color_compare_strings(diff_cmd string, expected string, found string) str
ctime := time.sys_mono_now() ctime := time.sys_mono_now()
e_file := os.join_path(cdir, '${ctime}.expected.txt') e_file := os.join_path(cdir, '${ctime}.expected.txt')
f_file := os.join_path(cdir, '${ctime}.found.txt') f_file := os.join_path(cdir, '${ctime}.found.txt')
os.write_file(e_file, expected) os.write_file(e_file, expected) or { panic(err) }
os.write_file(f_file, found) os.write_file(f_file, found) or { panic(err) }
res := color_compare_files(diff_cmd, e_file, f_file) res := color_compare_files(diff_cmd, e_file, f_file)
os.rm(e_file) os.rm(e_file) or { panic(err) }
os.rm(f_file) os.rm(f_file) or { panic(err) }
return res return res
} }

View File

@ -489,7 +489,7 @@ pub fn get_vtmp_folder() string {
} }
vtmp = os.join_path(os.temp_dir(), 'v') vtmp = os.join_path(os.temp_dir(), 'v')
if !os.exists(vtmp) || !os.is_dir(vtmp) { if !os.exists(vtmp) || !os.is_dir(vtmp) {
os.mkdir_all(vtmp) os.mkdir_all(vtmp) or { panic(err) }
} }
os.setenv('VTMP', vtmp, true) os.setenv('VTMP', vtmp, true)
return vtmp return vtmp

View File

@ -30,8 +30,8 @@ pub:
basepath string basepath string
original_vopts string original_vopts string
pub mut: pub mut:
vopts string vopts string
k2cpath map[string]string // key -> filesystem cache path for the object k2cpath map[string]string // key -> filesystem cache path for the object
} }
pub fn new_cache_manager(opts []string) CacheManager { pub fn new_cache_manager(opts []string) CacheManager {
@ -40,13 +40,13 @@ pub fn new_cache_manager(opts []string) CacheManager {
vcache_basepath = os.join_path(os.vmodules_dir(), 'cache') vcache_basepath = os.join_path(os.vmodules_dir(), 'cache')
} }
if !os.is_dir(vcache_basepath) { if !os.is_dir(vcache_basepath) {
os.mkdir_all(vcache_basepath) os.mkdir_all(vcache_basepath) or { panic(err) }
readme_content := 'This folder contains cached build artifacts from the V build system. readme_content := 'This folder contains cached build artifacts from the V build system.
|You can safely delete it, if it is getting too large. |You can safely delete it, if it is getting too large.
|It will be recreated the next time you compile something with V. |It will be recreated the next time you compile something with V.
|You can change its location with the VCACHE environment variable. |You can change its location with the VCACHE environment variable.
'.strip_margin() '.strip_margin()
os.write_file(os.join_path(vcache_basepath, 'README.md'), readme_content) os.write_file(os.join_path(vcache_basepath, 'README.md'), readme_content) or { panic(err) }
} }
original_vopts := opts.join('|') original_vopts := opts.join('|')
return CacheManager{ return CacheManager{
@ -74,7 +74,7 @@ pub fn (mut cm CacheManager) key2cpath(key string) string {
cprefix_folder := os.join_path(cm.basepath, prefix) cprefix_folder := os.join_path(cm.basepath, prefix)
cpath = os.join_path(cprefix_folder, khash) cpath = os.join_path(cprefix_folder, khash)
if !os.is_dir(cprefix_folder) { if !os.is_dir(cprefix_folder) {
os.mkdir_all(cprefix_folder) os.mkdir_all(cprefix_folder) or { panic(err) }
os.chmod(cprefix_folder, 0o777) os.chmod(cprefix_folder, 0o777)
} }
cm.k2cpath[key] = cpath cm.k2cpath[key] = cpath

View File

@ -17,7 +17,7 @@ fn check_cache_entry_fpath_invariants(x string, extension string) {
fn testsuite_begin() { fn testsuite_begin() {
os.setenv('VCACHE', vcache_folder, true) os.setenv('VCACHE', vcache_folder, true)
// eprintln('testsuite_begin, vcache_folder = $vcache_folder') // eprintln('testsuite_begin, vcache_folder = $vcache_folder')
os.rmdir_all(vcache_folder) os.rmdir_all(vcache_folder) or { }
vcache.new_cache_manager([]) vcache.new_cache_manager([])
assert os.is_dir(vcache_folder) assert os.is_dir(vcache_folder)
} }
@ -54,33 +54,25 @@ fn test_different_options_should_produce_different_cache_entries_for_same_key_an
fn test_exists() { fn test_exists() {
mut cm := vcache.new_cache_manager([]) mut cm := vcache.new_cache_manager([])
cm.exists('.o', 'abc') or { cm.exists('.o', 'abc') or { assert true }
assert true
}
// //
x := cm.save('.x', 'abc', '') or { x := cm.save('.x', 'abc', '') or {
assert false assert false
'' ''
} }
cm.exists('.o', 'abc') or { cm.exists('.o', 'abc') or { assert true }
assert true
}
// //
y := cm.save('.o', 'zbc', '') or { y := cm.save('.o', 'zbc', '') or {
assert false assert false
'' ''
} }
cm.exists('.o', 'abc') or { cm.exists('.o', 'abc') or { assert true }
assert true
}
// //
z := cm.save('.o', 'abc', '') or { z := cm.save('.o', 'abc', '') or {
assert false assert false
'' ''
} }
cm.exists('.o', 'abc') or { cm.exists('.o', 'abc') or { assert false }
assert false
}
// //
assert os.is_file(x) assert os.is_file(x)
assert os.is_file(y) assert os.is_file(y)
@ -104,6 +96,6 @@ fn test_readme_exists_and_is_readable() {
fn testsuite_end() { fn testsuite_end() {
os.chdir(os.wd_at_startup) os.chdir(os.wd_at_startup)
os.rmdir_all(vcache_folder) os.rmdir_all(vcache_folder) or { }
assert !os.is_dir(vcache_folder) assert !os.is_dir(vcache_folder)
} }

View File

@ -99,7 +99,7 @@ fn (am AssetManager) combine(asset_type string, to_file bool) string {
os.mkdir(am.cache_dir) or { panic(err) } os.mkdir(am.cache_dir) or { panic(err) }
} }
mut file := os.create(out_file) or { panic(err) } mut file := os.create(out_file) or { panic(err) }
file.write(out.bytes()) file.write(out.bytes()) or { panic(err) }
file.close() file.close()
return out_file return out_file
} }

View File

@ -6,7 +6,7 @@ import os
// unique cache dirs are needed per test function. // unique cache dirs are needed per test function.
fn clean_cache_dir(dir string) { fn clean_cache_dir(dir string) {
if os.is_dir(dir) { if os.is_dir(dir) {
os.rmdir_all(dir) os.rmdir_all(dir) or { panic(err) }
} }
} }
@ -21,10 +21,10 @@ fn cache_dir(test_name string) string {
fn get_test_file_path(file string) string { fn get_test_file_path(file string) string {
path := os.join_path(base_cache_dir(), file) path := os.join_path(base_cache_dir(), file)
if !os.is_dir(base_cache_dir()) { if !os.is_dir(base_cache_dir()) {
os.mkdir_all(base_cache_dir()) os.mkdir_all(base_cache_dir()) or { panic(err) }
} }
if !os.exists(path) { if !os.exists(path) {
os.write_file(path, get_test_file_contents(file)) os.write_file(path, get_test_file_contents(file)) or { panic(err) }
} }
return path return path
} }

View File

@ -20,7 +20,7 @@ const (
fn testsuite_begin() { fn testsuite_begin() {
os.chdir(vroot) os.chdir(vroot)
if os.exists(serverexe) { if os.exists(serverexe) {
os.rm(serverexe) os.rm(serverexe) or { }
} }
} }
@ -246,7 +246,7 @@ fn simple_tcp_client(config SimpleTcpClientConfig) ?string {
client.set_read_timeout(tcp_r_timeout) client.set_read_timeout(tcp_r_timeout)
client.set_write_timeout(tcp_w_timeout) client.set_write_timeout(tcp_w_timeout)
defer { defer {
client.close() client.close() or { }
} }
message := 'GET $config.path HTTP/1.1 message := 'GET $config.path HTTP/1.1
Host: $config.host Host: $config.host

View File

@ -355,7 +355,8 @@ fn handle_conn<T>(mut conn net.TcpConn, mut app T) {
//} //}
// read body // read body
mut read_body := []byte{len: len} mut read_body := []byte{len: len}
reader.read(mut read_body) // read just the amount of content len if there is no content there is nothing more to read here // read just the amount of content len if there is no content there is nothing more to read here
reader.read(mut read_body) or { println('reader.read failed with err: $err') }
body += read_body.bytestr() body += read_body.bytestr()
break break
} }

View File

@ -1,4 +1,5 @@
module ttf module ttf
/********************************************************************** /**********************************************************************
* *
* Common data for the module * Common data for the module
@ -15,8 +16,7 @@ import os
import math import math
// text align // text align
pub pub enum Text_align {
enum Text_align {
left left
center center
right right
@ -24,8 +24,7 @@ enum Text_align {
} }
// draw style // draw style
pub pub enum Style {
enum Style {
outline outline
outline_aliased outline_aliased
filled filled
@ -38,8 +37,9 @@ enum Style {
* *
******************************************************************************/ ******************************************************************************/
const debug_flag = false const debug_flag = false
fn dprintln(txt string){
if debug_flag { fn dprintln(txt string) {
if ttf.debug_flag {
println(txt) println(txt)
} }
} }
@ -50,34 +50,34 @@ fn dprintln(txt string){
* *
******************************************************************************/ ******************************************************************************/
// transform the bitmap from one layer to color layers // transform the bitmap from one layer to color layers
fn (mut bmp BitMap) format_texture(){ fn (mut bmp BitMap) format_texture() {
r := byte(bmp.color >> 24) r := byte(bmp.color >> 24)
g := byte((bmp.color >> 16) & 0xFF) g := byte((bmp.color >> 16) & 0xFF)
b := byte((bmp.color >> 8 ) & 0xFF) b := byte((bmp.color >> 8) & 0xFF)
a := byte(bmp.color & 0xFF) a := byte(bmp.color & 0xFF)
b_r := byte(bmp.bg_color >> 24) b_r := byte(bmp.bg_color >> 24)
b_g := byte((bmp.bg_color >> 16) & 0xFF) b_g := byte((bmp.bg_color >> 16) & 0xFF)
b_b := byte((bmp.bg_color >> 8 ) & 0xFF) b_b := byte((bmp.bg_color >> 8) & 0xFF)
b_a := byte(bmp.bg_color & 0xFF) b_a := byte(bmp.bg_color & 0xFF)
// trasform buffer in a texture // trasform buffer in a texture
x := byteptr(bmp.buf) x := byteptr(bmp.buf)
unsafe{ unsafe {
mut i := 0 mut i := 0
for i<bmp.buf_size { for i < bmp.buf_size {
data := x[i] data := x[i]
if data > 0 { if data > 0 {
x[i+0] = r x[i + 0] = r
x[i+1] = g x[i + 1] = g
x[i+2] = b x[i + 2] = b
// alpha // alpha
x[i+3] = byte((a * data) >> 8) x[i + 3] = byte((a * data) >> 8)
} else { } else {
x[i+0] = b_r x[i + 0] = b_r
x[i+1] = b_g x[i + 1] = b_g
x[i+2] = b_b x[i + 2] = b_b
x[i+3] = b_a x[i + 3] = b_a
} }
i += 4 i += 4
} }
@ -85,52 +85,49 @@ fn (mut bmp BitMap) format_texture(){
} }
// write out a .ppm file // write out a .ppm file
pub pub fn (mut bmp BitMap) save_as_ppm(file_name string) {
fn (mut bmp BitMap) save_as_ppm(file_name string) {
tmp_buf := bmp.buf tmp_buf := bmp.buf
mut buf := malloc(bmp.buf_size) mut buf := malloc(bmp.buf_size)
unsafe { C.memcpy(buf, tmp_buf, bmp.buf_size) } unsafe { C.memcpy(buf, tmp_buf, bmp.buf_size) }
bmp.buf = buf bmp.buf = buf
bmp.format_texture() bmp.format_texture()
npixels := bmp.width * bmp.height npixels := bmp.width * bmp.height
mut f_out := os.create(file_name) or { panic(err) } mut f_out := os.create(file_name) or { panic(err) }
f_out.writeln('P3') f_out.writeln('P3') or { panic(err) }
f_out.writeln('${bmp.width} ${bmp.height}') f_out.writeln('$bmp.width $bmp.height') or { panic(err) }
f_out.writeln('255') f_out.writeln('255') or { panic(err) }
for i in 0..npixels { for i in 0 .. npixels {
pos := i * bmp.bp pos := i * bmp.bp
unsafe { unsafe {
c_r := bmp.buf[pos] c_r := bmp.buf[pos]
c_g := bmp.buf[pos +1 ] c_g := bmp.buf[pos + 1]
c_b := bmp.buf[pos + 2] c_b := bmp.buf[pos + 2]
f_out.write_str('${c_r} ${c_g} ${c_b} ') f_out.write_str('$c_r $c_g $c_b ') or { panic(err) }
} }
} }
f_out.close() f_out.close()
free(buf) free(buf)
bmp.buf = tmp_buf bmp.buf = tmp_buf
} }
pub pub fn (mut bmp BitMap) get_raw_bytes() []byte {
fn (mut bmp BitMap) get_raw_bytes() []byte { mut f_buf := []byte{len: bmp.buf_size / 4}
mut f_buf := []byte{len: bmp.buf_size/4} mut i := 0
mut i:=0
for i < bmp.buf_size { for i < bmp.buf_size {
unsafe { f_buf[i>>2] = *(bmp.buf + i) } unsafe {
f_buf[i >> 2] = *(bmp.buf + i)
}
i += 4 i += 4
} }
return f_buf return f_buf
} }
pub pub fn (mut bmp BitMap) save_raw_data(file_name string) {
fn (mut bmp BitMap) save_raw_data(file_name string) { os.write_file_array(file_name, bmp.get_raw_bytes()) or { panic(err) }
os.write_file_array(file_name, bmp.get_raw_bytes())
} }
// //
// Math functions // Math functions
// //
@ -181,8 +178,7 @@ fn rfpart(x f32) f32 {
******************************************************************************/ ******************************************************************************/
/* /*
[inline] [inline]
pub pub fn (mut dev BitMap) get_color(x int, y int) (int, int, int, int){
fn (mut dev BitMap) get_color(x int, y int) (int, int, int, int){
if x < 0 || x >= dev.width || y < 0 || y >= dev.height { if x < 0 || x >= dev.width || y < 0 || y >= dev.height {
return 0,0,0,0 return 0,0,0,0
} }
@ -193,8 +189,7 @@ fn (mut dev BitMap) get_color(x int, y int) (int, int, int, int){
} }
[inline] [inline]
pub pub fn (mut dev BitMap) get_color_u32(x int, y int) u32{
fn (mut dev BitMap) get_color_u32(x int, y int) u32{
r, g, b, a := dev.get_color(x, y) r, g, b, a := dev.get_color(x, y)
unsafe{ unsafe{
return u32(r<<24) | u32(g<<16) | u32(b<<8) | u32(a) return u32(r<<24) | u32(g<<16) | u32(b<<8) | u32(a)
@ -207,18 +202,16 @@ fn (mut dev BitMap) get_color_u32(x int, y int) u32{
* *
******************************************************************************/ ******************************************************************************/
[inline] [inline]
pub pub fn color_multiply_alpha(c u32, level f32) u32 {
fn color_multiply_alpha(c u32, level f32) u32 { return u32(f32(c & 0xFF) * level)
return u32(f32( c & 0xFF) * level)
} }
[inline] [inline]
pub pub fn color_multiply(c u32, level f32) u32 {
fn color_multiply(c u32, level f32) u32 { mut r := (f32((c >> 24) & 0xFF) / 255.0) * level
mut r := (f32((c >> 24) & 0xFF)/255.0) * level mut g := (f32((c >> 16) & 0xFF) / 255.0) * level
mut g := (f32((c >> 16) & 0xFF)/255.0) * level mut b := (f32((c >> 8) & 0xFF) / 255.0) * level
mut b := (f32((c >> 8) & 0xFF)/255.0) * level mut a := (f32(c & 0xFF) / 255.0) * level
mut a := (f32( c & 0xFF)/255.0) * level
r = if r > 1.0 { 1.0 } else { r } r = if r > 1.0 { 1.0 } else { r }
g = if g > 1.0 { 1.0 } else { g } g = if g > 1.0 { 1.0 } else { g }
b = if b > 1.0 { 1.0 } else { b } b = if b > 1.0 { 1.0 } else { b }

View File

@ -1,4 +1,5 @@
module ttf module ttf
/********************************************************************** /**********************************************************************
* *
* BMP render module utility functions * BMP render module utility functions
@ -15,42 +16,33 @@ module ttf
import encoding.utf8 import encoding.utf8
import math import math
pub pub struct BitMap {
struct BitMap {
pub mut: pub mut:
tf &TTF_File tf &TTF_File
buf byteptr // pointer to the memory buffer
buf byteptr // pointer to the memory buffer
buf_size int // allocated buf size in bytes buf_size int // allocated buf size in bytes
width int = 1 // width of the buffer
width int =1 // width of the buffer height int = 1 // height of the buffer
height int =1 // height of the buffer bp int = 4 // byte per pixel of the buffer
bp int =4 // byte per pixel of the buffer bg_color u32 = 0xFFFFFF_00 // background RGBA format
color u32 = 0x000000_FF // RGBA format
bg_color u32 = 0xFFFFFF_00 // background RGBA format scale f32 = 1.0 // internal usage!!
color u32 = 0x000000_FF // RGBA format scale_x f32 = 1.0 // X scale of the single glyph
scale f32 = 1.0 // internal usage!! scale_y f32 = 1.0 // Y scale of the single glyph
scale_x f32 = 1.0 // X scale of the single glyph angle f32 = 0.0 // angle of rotation of the bitmap
scale_y f32 = 1.0 // Y scale of the single glyph
angle f32 = 0.0 // angle of rotation of the bitmap
// spaces // spaces
space_cw f32 = 1.0 // width of the space glyph internal usage!! space_cw f32 = 1.0 // width of the space glyph internal usage!!
space_mult f32 = f32(0.0) //1.0/16.0 // space between letter, is a multiplier for a standrd space ax space_mult f32 = f32(0.0) // 1.0/16.0 // space between letter, is a multiplier for a standrd space ax
// used only by internal text rendering!! // used only by internal text rendering!!
tr_matrix []f32 = [f32(1), 0, 0, 0, 1, 0, 0, 0, 0] // transformation matrix tr_matrix []f32 = [f32(1), 0, 0, 0, 1, 0, 0, 0, 0] // transformation matrix
ch_matrix []f32 = [f32(1), 0, 0, 0, 1, 0, 0, 0, 0] // character matrix ch_matrix []f32 = [f32(1), 0, 0, 0, 1, 0, 0, 0, 0] // character matrix
style Style = .filled // default syle style Style = .filled // default syle
align Text_align = .left // default text align align Text_align = .left // default text align
justify bool // justify text flag, default deactivated justify bool // justify text flag, default deactivated
justify_fill_ratio f32 = 0.5 // justify fill ratio, if the ratio of the filled row is >= of this then justify the text justify_fill_ratio f32 = 0.5 // justify fill ratio, if the ratio of the filled row is >= of this then justify the text
filler [][]int // filler buffer for the renderer
filler [][]int // filler buffer for the renderer
// flag to force font embedded metrics // flag to force font embedded metrics
use_font_metrics bool use_font_metrics bool
} }
/****************************************************************************** /******************************************************************************
@ -59,8 +51,7 @@ pub mut:
* *
******************************************************************************/ ******************************************************************************/
// clear clear the bitmap with 0 bytes // clear clear the bitmap with 0 bytes
pub pub fn (mut bmp BitMap) clear() {
fn (mut bmp BitMap) clear() {
mut sz := bmp.width * bmp.height * bmp.bp mut sz := bmp.width * bmp.height * bmp.bp
unsafe { unsafe {
C.memset(bmp.buf, 0x00, sz) C.memset(bmp.buf, 0x00, sz)
@ -69,30 +60,28 @@ fn (mut bmp BitMap) clear() {
// transform matrix applied to the text // transform matrix applied to the text
fn (bmp &BitMap) trf_txt(p &Point) (int, int) { fn (bmp &BitMap) trf_txt(p &Point) (int, int) {
return int(p.x * bmp.tr_matrix[0] + p.y * bmp.tr_matrix[3] + bmp.tr_matrix[6]), return int(p.x * bmp.tr_matrix[0] + p.y * bmp.tr_matrix[3] + bmp.tr_matrix[6]), int(
int(p.x * bmp.tr_matrix[1] + p.y * bmp.tr_matrix[4] + bmp.tr_matrix[7]) p.x * bmp.tr_matrix[1] + p.y * bmp.tr_matrix[4] + bmp.tr_matrix[7])
} }
// transform matrix applied to the char // transform matrix applied to the char
fn (bmp &BitMap) trf_ch(p &Point) (int, int) { fn (bmp &BitMap) trf_ch(p &Point) (int, int) {
return int(p.x * bmp.ch_matrix[0] + p.y * bmp.ch_matrix[3] + bmp.ch_matrix[6]), return int(p.x * bmp.ch_matrix[0] + p.y * bmp.ch_matrix[3] + bmp.ch_matrix[6]), int(
int(p.x * bmp.ch_matrix[1] + p.y * bmp.ch_matrix[4] + bmp.ch_matrix[7]) p.x * bmp.ch_matrix[1] + p.y * bmp.ch_matrix[4] + bmp.ch_matrix[7])
} }
// set draw postion in the buffer // set draw postion in the buffer
pub pub fn (mut bmp BitMap) set_pos(x f32, y f32) {
fn (mut bmp BitMap) set_pos(x f32, y f32) { bmp.tr_matrix[6] = x
bmp.tr_matrix[6] = x bmp.tr_matrix[7] = y
bmp.tr_matrix[7] = y
} }
// set the rotation angle in radiants // set the rotation angle in radiants
pub pub fn (mut bmp BitMap) set_rotation(a f32) {
fn (mut bmp BitMap) set_rotation(a f32) { bmp.tr_matrix[0] = f32(math.cos(a)) // 1
bmp.tr_matrix[0] = f32(math.cos(a)) //1 bmp.tr_matrix[1] = f32(-math.sin(a)) // 0
bmp.tr_matrix[1] = f32(-math.sin(a)) //0 bmp.tr_matrix[3] = f32(math.sin(a)) // 0
bmp.tr_matrix[3] = f32(math.sin(a)) //0 bmp.tr_matrix[4] = f32(math.cos(a)) // 1
bmp.tr_matrix[4] = f32(math.cos(a)) //1
} }
/****************************************************************************** /******************************************************************************
@ -100,43 +89,40 @@ fn (mut bmp BitMap) set_rotation(a f32) {
* Filler functions * Filler functions
* *
******************************************************************************/ ******************************************************************************/
pub pub fn (mut bmp BitMap) init_filler() {
fn (mut bmp BitMap) init_filler() { h := bmp.height - bmp.filler.len
h := bmp.height - bmp.filler.len
if h < 1 { if h < 1 {
return return
} }
for _ in 0..h { for _ in 0 .. h {
bmp.filler << []int{len:4} bmp.filler << []int{len: 4}
} }
// dprintln("Init filler: ${bmp.filler.len} rows") // dprintln("Init filler: ${bmp.filler.len} rows")
} }
pub pub fn (mut bmp BitMap) clear_filler() {
fn (mut bmp BitMap) clear_filler() { for i in 0 .. bmp.height {
for i in 0..bmp.height {
bmp.filler[i].clear() bmp.filler[i].clear()
} }
} }
pub pub fn (mut bmp BitMap) exec_filler() {
fn (mut bmp BitMap) exec_filler() { for y in 0 .. bmp.height {
for y in 0..bmp.height {
if bmp.filler[y].len > 0 { if bmp.filler[y].len > 0 {
bmp.filler[y].sort() bmp.filler[y].sort()
if bmp.filler[y].len & 1 != 0 { if bmp.filler[y].len & 1 != 0 {
//dprintln("even line!! $y => ${bmp.filler[y]}") // dprintln("even line!! $y => ${bmp.filler[y]}")
continue continue
} }
mut index := 0 mut index := 0
for index < bmp.filler[y].len { for index < bmp.filler[y].len {
startx := bmp.filler[y][index] + 1 startx := bmp.filler[y][index] + 1
endx := bmp.filler[y][index+1] endx := bmp.filler[y][index + 1]
if startx >= endx { if startx >= endx {
index += 2 index += 2
continue continue
} }
for x in startx..endx { for x in startx .. endx {
bmp.plot(x, y, bmp.color) bmp.plot(x, y, bmp.color)
} }
index += 2 index += 2
@ -145,8 +131,7 @@ fn (mut bmp BitMap) exec_filler() {
} }
} }
pub pub fn (mut bmp BitMap) fline(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
fn (mut bmp BitMap) fline(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
mut x0 := f32(in_x0) mut x0 := f32(in_x0)
mut x1 := f32(in_x1) mut x1 := f32(in_x1)
mut y0 := f32(in_y0) mut y0 := f32(in_y0)
@ -170,7 +155,7 @@ fn (mut bmp BitMap) fline(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
mut dx := x1 - x0 mut dx := x1 - x0
mut dy := y1 - y0 mut dy := y1 - y0
if dy == 0 { if dy == 0 {
if in_y0 >= 0 && in_y0 < bmp.filler.len { if in_y0 >= 0 && in_y0 < bmp.filler.len {
if in_x0 <= in_x1 { if in_x0 <= in_x1 {
@ -184,15 +169,15 @@ fn (mut bmp BitMap) fline(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
return return
} }
mut n := dx / dy mut n := dx / dy
for y in 0..int(dy+0.5) { for y in 0 .. int(dy + 0.5) {
yd := int(y + y0) yd := int(y + y0)
x := n * y + x0 x := n * y + x0
if x > bmp.width || yd >= bmp.filler.len { if x > bmp.width || yd >= bmp.filler.len {
break break
} }
if yd >= 0 && yd < bmp.filler.len { if yd >= 0 && yd < bmp.filler.len {
bmp.filler[yd] << int(x+0.5) bmp.filler[yd] << int(x + 0.5)
//bmp.plot(int(x+0.5), yd, bmp.color) // bmp.plot(int(x+0.5), yd, bmp.color)
} }
} }
} }
@ -203,23 +188,22 @@ fn (mut bmp BitMap) fline(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
* *
******************************************************************************/ ******************************************************************************/
[inline] [inline]
pub pub fn (mut bmp BitMap) plot(x int, y int, c u32) bool {
fn (mut bmp BitMap) plot(x int, y int, c u32) bool {
if x < 0 || x >= bmp.width || y < 0 || y >= bmp.height { if x < 0 || x >= bmp.width || y < 0 || y >= bmp.height {
return false return false
} }
mut index := (x + y * bmp.width) * bmp.bp mut index := (x + y * bmp.width) * bmp.bp
unsafe { unsafe {
//bmp.buf[index]=0xFF // bmp.buf[index]=0xFF
bmp.buf[index] = byte(c & 0xFF) // write only the alpha bmp.buf[index] = byte(c & 0xFF) // write only the alpha
} }
/* /*
for count in 0..(bmp.bp) { for count in 0..(bmp.bp) {
unsafe{ unsafe{
bmp.buf[index + count] = byte((c >> (bmp.bp - count - 1) * 8) & 0x0000_00FF) bmp.buf[index + count] = byte((c >> (bmp.bp - count - 1) * 8) & 0x0000_00FF)
} }
} }
*/ */
return true return true
} }
@ -229,9 +213,8 @@ fn (mut bmp BitMap) plot(x int, y int, c u32) bool {
* *
******************************************************************************/ ******************************************************************************/
// aline draw an aliased line on the bitmap // aline draw an aliased line on the bitmap
pub pub fn (mut bmp BitMap) aline(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
fn (mut bmp BitMap) aline(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) { // mut c1 := c
//mut c1 := c
mut x0 := f32(in_x0) mut x0 := f32(in_x0)
mut x1 := f32(in_x1) mut x1 := f32(in_x1)
mut y0 := f32(in_y0) mut y0 := f32(in_y0)
@ -263,11 +246,11 @@ fn (mut bmp BitMap) aline(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
mut x := x0 mut x := x0
for x <= x1 + 0.5 { for x <= x1 + 0.5 {
y := m * (x - x0) + y0 y := m * (x - x0) + y0
e := 1-fabs(y-0.5-int(y)) e := 1 - fabs(y - 0.5 - int(y))
bmp.plot(int(x), int(y), color_multiply_alpha(c, e*0.75)) bmp.plot(int(x), int(y), color_multiply_alpha(c, e * 0.75))
ys1 := y + dist ys1 := y + dist
if int(ys1) != int(y){ if int(ys1) != int(y) {
v1 := fabs(ys1 - y) / dist * (1 - e) v1 := fabs(ys1 - y) / dist * (1 - e)
bmp.plot(int(x), int(ys1), color_multiply_alpha(c, v1)) bmp.plot(int(x), int(ys1), color_multiply_alpha(c, v1))
} }
@ -280,7 +263,6 @@ fn (mut bmp BitMap) aline(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
x += 1.0 x += 1.0
} }
} else { } else {
if y1 < y0 { if y1 < y0 {
tmp = x0 tmp = x0
@ -302,7 +284,7 @@ fn (mut bmp BitMap) aline(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
for y <= y1 + 0.5 { for y <= y1 + 0.5 {
x := n * (y - y0) + x0 x := n * (y - y0) + x0
e := f32(1 - fabs(x - 0.5 - int(x))) e := f32(1 - fabs(x - 0.5 - int(x)))
bmp.plot(int(x), int(y), color_multiply_alpha(c, f32(e*0.75))) bmp.plot(int(x), int(y), color_multiply_alpha(c, f32(e * 0.75)))
xs1 := x + dist xs1 := x + dist
if int(xs1) != int(x) { if int(xs1) != int(x) {
@ -325,9 +307,7 @@ fn (mut bmp BitMap) aline(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
* draw functions * draw functions
* *
******************************************************************************/ ******************************************************************************/
pub pub fn (mut bmp BitMap) line(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
fn (mut bmp BitMap) line(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
// outline with aliased borders // outline with aliased borders
if bmp.style == .outline_aliased { if bmp.style == .outline_aliased {
bmp.aline(in_x0, in_y0, in_x1, in_y1, c) bmp.aline(in_x0, in_y0, in_x1, in_y1, c)
@ -350,7 +330,7 @@ fn (mut bmp BitMap) line(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
x1 := int(in_x1) x1 := int(in_x1)
y0 := int(in_y0) y0 := int(in_y0)
y1 := int(in_y1) y1 := int(in_y1)
//dprintln("line[$x0,$y0,$x1,$y1]") // dprintln("line[$x0,$y0,$x1,$y1]")
mut x := x0 mut x := x0
mut y := y0 mut y := y0
@ -359,28 +339,28 @@ fn (mut bmp BitMap) line(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
sx := if x0 < x1 { 1 } else { -1 } sx := if x0 < x1 { 1 } else { -1 }
dy := -abs(y1 - y0) dy := -abs(y1 - y0)
sy := if y0 < y1 { 1 } else { -1 } sy := if y0 < y1 { 1 } else { -1 }
// verical line // verical line
if dx == 0 { if dx == 0 {
if y0 < y1 { if y0 < y1 {
for yt in y0..y1+1 { for yt in y0 .. y1 + 1 {
bmp.plot(x0, yt, c) bmp.plot(x0, yt, c)
} }
return return
} }
for yt in y1..y0+1 { for yt in y1 .. y0 + 1 {
bmp.plot(x0, yt, c) bmp.plot(x0, yt, c)
} }
// horizontal line
return return
// horizontal line } else if dy == 0 {
} else if dy == 0{
if x0 < x1 { if x0 < x1 {
for xt in x0..x1+1 { for xt in x0 .. x1 + 1 {
bmp.plot(xt, y0, c) bmp.plot(xt, y0, c)
} }
return return
} }
for xt in x1..x0+1 { for xt in x1 .. x0 + 1 {
bmp.plot(xt, y0, c) bmp.plot(xt, y0, c)
} }
return return
@ -388,10 +368,10 @@ fn (mut bmp BitMap) line(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
mut err := dx + dy // error value e_xy mut err := dx + dy // error value e_xy
for { for {
//bmp.plot(x, y, u32(0xFF00)) // bmp.plot(x, y, u32(0xFF00))
bmp.plot(x, y, c) bmp.plot(x, y, c)
//dprintln("$x $y [$x0,$y0,$x1,$y1]") // dprintln("$x $y [$x0,$y0,$x1,$y1]")
if x == x1 && y == y1 { if x == x1 && y == y1 {
break break
} }
@ -405,20 +385,16 @@ fn (mut bmp BitMap) line(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
y += sy y += sy
} }
} }
} }
pub fn (mut bmp BitMap) box(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
pub
fn (mut bmp BitMap) box(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
bmp.line(in_x0, in_y0, in_x1, in_y0, c) bmp.line(in_x0, in_y0, in_x1, in_y0, c)
bmp.line(in_x1, in_y0, in_x1, in_y1, c) bmp.line(in_x1, in_y0, in_x1, in_y1, c)
bmp.line(in_x0, in_y1, in_x1, in_y1, c) bmp.line(in_x0, in_y1, in_x1, in_y1, c)
bmp.line(in_x0, in_y0, in_x0, in_y1, c) bmp.line(in_x0, in_y0, in_x0, in_y1, c)
} }
pub pub fn (mut bmp BitMap) quadratic(in_x0 int, in_y0 int, in_x1 int, in_y1 int, in_cx int, in_cy int, c u32) {
fn (mut bmp BitMap) quadratic(in_x0 int, in_y0 int, in_x1 int, in_y1 int, in_cx int, in_cy int, c u32) {
/* /*
x0 := int(in_x0 * bmp.scale) x0 := int(in_x0 * bmp.scale)
x1 := int(in_x1 * bmp.scale) x1 := int(in_x1 * bmp.scale)
@ -437,41 +413,41 @@ fn (mut bmp BitMap) quadratic(in_x0 int, in_y0 int, in_x1 int, in_y1 int, in_cx
mut division := f64(1.0) mut division := f64(1.0)
dx := abs(x0 - x1) dx := abs(x0 - x1)
dy := abs(y0 - y1) dy := abs(y0 - y1)
// if few pixel draw a simple line // if few pixel draw a simple line
//if dx == 0 && dy == 0 { // if dx == 0 && dy == 0 {
if dx <= 2 || dy <= 2 { if dx <= 2 || dy <= 2 {
//bmp.plot(x0, y0, c) // bmp.plot(x0, y0, c)
bmp.line(x0,y0,x1,y1, c) bmp.line(x0, y0, x1, y1, c)
return return
} }
division = 1.0/(f64( if dx>dy {dx} else {dy} )) division = 1.0 / (f64(if dx > dy { dx } else { dy }))
//division = 0.1 // 10 division // division = 0.1 // 10 division
//division = 0.25 // 4 division // division = 0.25 // 4 division
//dprintln("div: $division") // dprintln("div: $division")
/* /*
----- Bezier quadratic form ----- ----- Bezier quadratic form -----
t = 0.5; // given example value, half length of the curve t = 0.5; // given example value, half length of the curve
x = (1 - t) * (1 - t) * p[0].x + 2 * (1 - t) * t * p[1].x + t * t * p[2].x; x = (1 - t) * (1 - t) * p[0].x + 2 * (1 - t) * t * p[1].x + t * t * p[2].x;
y = (1 - t) * (1 - t) * p[0].y + 2 * (1 - t) * t * p[1].y + t * t * p[2].y; y = (1 - t) * (1 - t) * p[0].y + 2 * (1 - t) * t * p[1].y + t * t * p[2].y;
--------------------------------- ---------------------------------
*/ */
mut x_old := x0 mut x_old := x0
mut y_old := y0 mut y_old := y0
mut t := 0.0 mut t := 0.0
for t <= (1.0 + division/2.0){ for t <= (1.0 + division / 2.0) {
s := 1.0 - t s := 1.0 - t
x := s * s * x0 + 2.0 * s * t * cx + t * t * x1 x := s * s * x0 + 2.0 * s * t * cx + t * t * x1
y := s * s * y0 + 2.0 * s * t * cy + t * t * y1 y := s * s * y0 + 2.0 * s * t * cy + t * t * y1
xi := int(x + 0.5) xi := int(x + 0.5)
yi := int(y + 0.5) yi := int(y + 0.5)
//bmp.plot(xi, yi, c) // bmp.plot(xi, yi, c)
bmp.line(x_old, y_old, xi, yi, c) bmp.line(x_old, y_old, xi, yi, c)
x_old = xi x_old = xi
y_old = yi y_old = yi
@ -484,14 +460,13 @@ fn (mut bmp BitMap) quadratic(in_x0 int, in_y0 int, in_x1 int, in_y1 int, in_cx
* TTF Query functions * TTF Query functions
* *
******************************************************************************/ ******************************************************************************/
pub pub fn (mut bmp BitMap) get_chars_bbox(in_string string) []int {
fn (mut bmp BitMap) get_chars_bbox(in_string string) []int {
mut res := []int{} mut res := []int{}
mut w := 0 mut w := 0
mut space_cw, _ := bmp.tf.get_horizontal_metrics(u16(` `)) mut space_cw, _ := bmp.tf.get_horizontal_metrics(u16(` `))
div_space_cw := int((f32(space_cw) * bmp.space_mult) * bmp.scale) div_space_cw := int((f32(space_cw) * bmp.space_mult) * bmp.scale)
space_cw = int(space_cw * bmp.scale) space_cw = int(space_cw * bmp.scale)
bmp.tf.reset_kern() bmp.tf.reset_kern()
@ -505,15 +480,14 @@ fn (mut bmp BitMap) get_chars_bbox(in_string string) []int {
i++ i++
continue continue
} }
// manage unicode chars like latin greek etc // manage unicode chars like latin greek etc
c_len := ((0xe5000000>>((char>>3) & 0x1e)) & 3) + 1 c_len := ((0xe5000000 >> ((char >> 3) & 0x1e)) & 3) + 1
if c_len > 1 { if c_len > 1 {
tmp_char := utf8.get_uchar(in_string,i) tmp_char := utf8.get_uchar(in_string, i)
//dprintln("tmp_char: ${tmp_char.hex()}") // dprintln("tmp_char: ${tmp_char.hex()}")
char = u16(tmp_char) char = u16(tmp_char)
} }
c_index := bmp.tf.map_code(int(char)) c_index := bmp.tf.map_code(int(char))
// Glyph not found // Glyph not found
if c_index == 0 { if c_index == 0 {
@ -522,18 +496,18 @@ fn (mut bmp BitMap) get_chars_bbox(in_string string) []int {
continue continue
} }
ax , ay := bmp.tf.next_kern(c_index) ax, ay := bmp.tf.next_kern(c_index)
//dprintln("char_index: $c_index ax: $ax ay: $ay") // dprintln("char_index: $c_index ax: $ax ay: $ay")
// cw, lsb := bmp.tf.get_horizontal_metrics(u16(char))
// dprintln("metrics: [${u16(char):c}] cw:$cw lsb:$lsb")
//cw, lsb := bmp.tf.get_horizontal_metrics(u16(char))
//dprintln("metrics: [${u16(char):c}] cw:$cw lsb:$lsb")
//----- Calc Glyph transformations ----- //----- Calc Glyph transformations -----
mut x0 := w + int(ax * bmp.scale) mut x0 := w + int(ax * bmp.scale)
mut y0 := 0 + int(ay * bmp.scale) mut y0 := 0 + int(ay * bmp.scale)
p := Point{x0,y0,false} p := Point{x0, y0, false}
x1 , y1 := bmp.trf_txt(p) x1, y1 := bmp.trf_txt(p)
// init ch_matrix // init ch_matrix
bmp.ch_matrix[0] = bmp.tr_matrix[0] * bmp.scale * bmp.scale_x bmp.ch_matrix[0] = bmp.tr_matrix[0] * bmp.scale * bmp.scale_x
bmp.ch_matrix[1] = bmp.tr_matrix[1] * bmp.scale * bmp.scale_x bmp.ch_matrix[1] = bmp.tr_matrix[1] * bmp.scale * bmp.scale_x
@ -542,29 +516,28 @@ fn (mut bmp BitMap) get_chars_bbox(in_string string) []int {
bmp.ch_matrix[6] = int(x1) bmp.ch_matrix[6] = int(x1)
bmp.ch_matrix[7] = int(y1) bmp.ch_matrix[7] = int(y1)
//x_min, x_max, y_min, y_max := bmp.tf.read_glyph_dim(c_index) // x_min, x_max, y_min, y_max := bmp.tf.read_glyph_dim(c_index)
x_min, x_max, _, _ := bmp.tf.read_glyph_dim(c_index) x_min, x_max, _, _ := bmp.tf.read_glyph_dim(c_index)
//----------------- //-----------------
width := int( (abs(x_max + x_min) + ax) * bmp.scale) width := int((abs(x_max + x_min) + ax) * bmp.scale)
//width := int((cw+ax) * bmp.scale) // width := int((cw+ax) * bmp.scale)
w += width + div_space_cw w += width + div_space_cw
h := int(abs(int(bmp.tf.y_max - bmp.tf.y_min)) * bmp.scale) h := int(abs(int(bmp.tf.y_max - bmp.tf.y_min)) * bmp.scale)
res << w res << w
res << h res << h
i+= c_len i += c_len
} }
return res return res
} }
pub pub fn (mut bmp BitMap) get_bbox(in_string string) (int, int) {
fn (mut bmp BitMap) get_bbox(in_string string) (int, int){
mut w := 0 mut w := 0
mut space_cw, _ := bmp.tf.get_horizontal_metrics(u16(` `)) mut space_cw, _ := bmp.tf.get_horizontal_metrics(u16(` `))
div_space_cw := int((f32(space_cw) * bmp.space_mult) * bmp.scale) div_space_cw := int((f32(space_cw) * bmp.space_mult) * bmp.scale)
space_cw = int(space_cw * bmp.scale) space_cw = int(space_cw * bmp.scale)
bmp.tf.reset_kern() bmp.tf.reset_kern()
@ -578,15 +551,14 @@ fn (mut bmp BitMap) get_bbox(in_string string) (int, int){
i++ i++
continue continue
} }
// manage unicode chars like latin greek etc // manage unicode chars like latin greek etc
c_len := ((0xe5000000>>((char>>3) & 0x1e)) & 3) + 1 c_len := ((0xe5000000 >> ((char >> 3) & 0x1e)) & 3) + 1
if c_len > 1 { if c_len > 1 {
tmp_char := utf8.get_uchar(in_string,i) tmp_char := utf8.get_uchar(in_string, i)
//dprintln("tmp_char: ${tmp_char.hex()}") // dprintln("tmp_char: ${tmp_char.hex()}")
char = u16(tmp_char) char = u16(tmp_char)
} }
c_index := bmp.tf.map_code(int(char)) c_index := bmp.tf.map_code(int(char))
// Glyph not found // Glyph not found
if c_index == 0 { if c_index == 0 {
@ -594,18 +566,18 @@ fn (mut bmp BitMap) get_bbox(in_string string) (int, int){
i += c_len i += c_len
continue continue
} }
ax , ay := bmp.tf.next_kern(c_index) ax, ay := bmp.tf.next_kern(c_index)
//dprintln("char_index: $c_index ax: $ax ay: $ay") // dprintln("char_index: $c_index ax: $ax ay: $ay")
// cw, lsb := bmp.tf.get_horizontal_metrics(u16(char))
// dprintln("metrics: [${u16(char):c}] cw:$cw lsb:$lsb")
//cw, lsb := bmp.tf.get_horizontal_metrics(u16(char))
//dprintln("metrics: [${u16(char):c}] cw:$cw lsb:$lsb")
//----- Calc Glyph transformations ----- //----- Calc Glyph transformations -----
mut x0 := w + int(ax * bmp.scale) mut x0 := w + int(ax * bmp.scale)
mut y0 := 0 + int(ay * bmp.scale) mut y0 := 0 + int(ay * bmp.scale)
p := Point{x0,y0,false} p := Point{x0, y0, false}
x1 , y1 := bmp.trf_txt(p) x1, y1 := bmp.trf_txt(p)
// init ch_matrix // init ch_matrix
bmp.ch_matrix[0] = bmp.tr_matrix[0] * bmp.scale * bmp.scale_x bmp.ch_matrix[0] = bmp.tr_matrix[0] * bmp.scale * bmp.scale_x
bmp.ch_matrix[1] = bmp.tr_matrix[1] * bmp.scale * bmp.scale_x bmp.ch_matrix[1] = bmp.tr_matrix[1] * bmp.scale * bmp.scale_x
@ -615,20 +587,20 @@ fn (mut bmp BitMap) get_bbox(in_string string) (int, int){
bmp.ch_matrix[7] = int(y1) bmp.ch_matrix[7] = int(y1)
x_min, x_max, _, _ := bmp.tf.read_glyph_dim(c_index) x_min, x_max, _, _ := bmp.tf.read_glyph_dim(c_index)
//x_min := 1 // x_min := 1
//x_max := 2 // x_max := 2
//----------------- //-----------------
width := int( (abs(x_max + x_min) + ax) * bmp.scale) width := int((abs(x_max + x_min) + ax) * bmp.scale)
//width := int((cw+ax) * bmp.scale) // width := int((cw+ax) * bmp.scale)
w += width + div_space_cw w += width + div_space_cw
i+= c_len i += c_len
} }
//dprintln("y_min: $bmp.tf.y_min y_max: $bmp.tf.y_max res: ${int((bmp.tf.y_max - bmp.tf.y_min)*buf.scale)} width: ${int( (cw) * buf.scale)}") // dprintln("y_min: $bmp.tf.y_min y_max: $bmp.tf.y_max res: ${int((bmp.tf.y_max - bmp.tf.y_min)*buf.scale)} width: ${int( (cw) * buf.scale)}")
//buf.box(0,y_base - int((bmp.tf.y_min)*buf.scale), int( (x_max) * buf.scale), y_base-int((bmp.tf.y_max)*buf.scale), u32(0xFF00_0000) ) // buf.box(0,y_base - int((bmp.tf.y_min)*buf.scale), int( (x_max) * buf.scale), y_base-int((bmp.tf.y_max)*buf.scale), u32(0xFF00_0000) )
return w , int(abs(int(bmp.tf.y_max - bmp.tf.y_min)) * bmp.scale) return w, int(abs(int(bmp.tf.y_max - bmp.tf.y_min)) * bmp.scale)
} }
/****************************************************************************** /******************************************************************************
@ -638,7 +610,7 @@ fn (mut bmp BitMap) get_bbox(in_string string) (int, int){
******************************************************************************/ ******************************************************************************/
fn (mut bmp BitMap) draw_notdef_glyph(in_x int, in_w int) { fn (mut bmp BitMap) draw_notdef_glyph(in_x int, in_w int) {
mut p := Point{in_x, 0, false} mut p := Point{in_x, 0, false}
x1 , y1 := bmp.trf_txt(p) x1, y1 := bmp.trf_txt(p)
// init ch_matrix // init ch_matrix
bmp.ch_matrix[0] = bmp.tr_matrix[0] * bmp.scale * bmp.scale_x bmp.ch_matrix[0] = bmp.tr_matrix[0] * bmp.scale * bmp.scale_x
bmp.ch_matrix[1] = bmp.tr_matrix[1] * bmp.scale * bmp.scale_x bmp.ch_matrix[1] = bmp.tr_matrix[1] * bmp.scale * bmp.scale_x
@ -646,22 +618,21 @@ fn (mut bmp BitMap) draw_notdef_glyph(in_x int, in_w int) {
bmp.ch_matrix[4] = bmp.tr_matrix[4] * -bmp.scale * bmp.scale_y bmp.ch_matrix[4] = bmp.tr_matrix[4] * -bmp.scale * bmp.scale_y
bmp.ch_matrix[6] = int(x1) bmp.ch_matrix[6] = int(x1)
bmp.ch_matrix[7] = int(y1) bmp.ch_matrix[7] = int(y1)
x,y := bmp.trf_ch(p) x, y := bmp.trf_ch(p)
y_h := fabs(bmp.tf.y_max-bmp.tf.y_min)* bmp.scale * 0.5 y_h := fabs(bmp.tf.y_max - bmp.tf.y_min) * bmp.scale * 0.5
bmp.box(int(x), int(y), int(x - in_w), int(y - y_h), bmp.color) bmp.box(int(x), int(y), int(x - in_w), int(y - y_h), bmp.color)
bmp.line(int(x), int(y), int(x - in_w ), int(y - y_h), bmp.color) bmp.line(int(x), int(y), int(x - in_w), int(y - y_h), bmp.color)
bmp.line(int(x - in_w ), int(y), int(x), int(y - y_h), bmp.color) bmp.line(int(x - in_w), int(y), int(x), int(y - y_h), bmp.color)
} }
pub pub fn (mut bmp BitMap) draw_text(in_string string) (int, int) {
fn (mut bmp BitMap) draw_text(in_string string) (int, int){
mut w := 0 mut w := 0
mut space_cw, _ := bmp.tf.get_horizontal_metrics(u16(` `)) mut space_cw, _ := bmp.tf.get_horizontal_metrics(u16(` `))
div_space_cw := int((f32(space_cw) * bmp.space_mult) * bmp.scale) div_space_cw := int((f32(space_cw) * bmp.space_mult) * bmp.scale)
space_cw = int(space_cw * bmp.scale) space_cw = int(space_cw * bmp.scale)
bmp.tf.reset_kern() bmp.tf.reset_kern()
@ -675,15 +646,14 @@ fn (mut bmp BitMap) draw_text(in_string string) (int, int){
i++ i++
continue continue
} }
// manage unicode chars like latin greek etc // manage unicode chars like latin greek etc
c_len := ((0xe5000000>>((char>>3) & 0x1e)) & 3) + 1 c_len := ((0xe5000000 >> ((char >> 3) & 0x1e)) & 3) + 1
if c_len > 1 { if c_len > 1 {
tmp_char := utf8.get_uchar(in_string,i) tmp_char := utf8.get_uchar(in_string, i)
//dprintln("tmp_char: ${tmp_char.hex()}") // dprintln("tmp_char: ${tmp_char.hex()}")
char = u16(tmp_char) char = u16(tmp_char)
} }
c_index := bmp.tf.map_code(int(char)) c_index := bmp.tf.map_code(int(char))
// Glyph not found // Glyph not found
if c_index == 0 { if c_index == 0 {
@ -693,19 +663,19 @@ fn (mut bmp BitMap) draw_text(in_string string) (int, int){
continue continue
} }
ax , ay := bmp.tf.next_kern(c_index) ax, ay := bmp.tf.next_kern(c_index)
//dprintln("char_index: $c_index ax: $ax ay: $ay") // dprintln("char_index: $c_index ax: $ax ay: $ay")
cw, _ := bmp.tf.get_horizontal_metrics(u16(char)) cw, _ := bmp.tf.get_horizontal_metrics(u16(char))
//cw, lsb := bmp.tf.get_horizontal_metrics(u16(char)) // cw, lsb := bmp.tf.get_horizontal_metrics(u16(char))
//dprintln("metrics: [${u16(char):c}] cw:$cw lsb:$lsb") // dprintln("metrics: [${u16(char):c}] cw:$cw lsb:$lsb")
//----- Draw_Glyph transformations ----- //----- Draw_Glyph transformations -----
mut x0 := w + int(ax * bmp.scale) mut x0 := w + int(ax * bmp.scale)
mut y0 := 0 + int(ay * bmp.scale) mut y0 := 0 + int(ay * bmp.scale)
p := Point{x0,y0,false} p := Point{x0, y0, false}
x1 , y1 := bmp.trf_txt(p) x1, y1 := bmp.trf_txt(p)
// init ch_matrix // init ch_matrix
bmp.ch_matrix[0] = bmp.tr_matrix[0] * bmp.scale * bmp.scale_x bmp.ch_matrix[0] = bmp.tr_matrix[0] * bmp.scale * bmp.scale_x
bmp.ch_matrix[1] = bmp.tr_matrix[1] * bmp.scale * bmp.scale_x bmp.ch_matrix[1] = bmp.tr_matrix[1] * bmp.scale * bmp.scale_x
@ -719,23 +689,22 @@ fn (mut bmp BitMap) draw_text(in_string string) (int, int){
// x_max := 2 // x_max := 2
//----------------- //-----------------
mut width := int( (abs(x_max + x_min) + ax) * bmp.scale) mut width := int((abs(x_max + x_min) + ax) * bmp.scale)
if bmp.use_font_metrics { if bmp.use_font_metrics {
width = int((cw+ax) * bmp.scale) width = int((cw + ax) * bmp.scale)
} }
w += width + div_space_cw w += width + div_space_cw
i+= c_len i += c_len
} }
//dprintln("y_min: $bmp.tf.y_min y_max: $bmp.tf.y_max res: ${int((bmp.tf.y_max - bmp.tf.y_min)*buf.scale)} width: ${int( (cw) * buf.scale)}") // dprintln("y_min: $bmp.tf.y_min y_max: $bmp.tf.y_max res: ${int((bmp.tf.y_max - bmp.tf.y_min)*buf.scale)} width: ${int( (cw) * buf.scale)}")
//buf.box(0,y_base - int((bmp.tf.y_min)*buf.scale), int( (x_max) * buf.scale), y_base-int((bmp.tf.y_max)*buf.scale), u32(0xFF00_0000) ) // buf.box(0,y_base - int((bmp.tf.y_min)*buf.scale), int( (x_max) * buf.scale), y_base-int((bmp.tf.y_max)*buf.scale), u32(0xFF00_0000) )
return w , int(abs(int(bmp.tf.y_max - bmp.tf.y_min)) * bmp.scale) return w, int(abs(int(bmp.tf.y_max - bmp.tf.y_min)) * bmp.scale)
} }
pub pub fn (mut bmp BitMap) draw_glyph(index u16) (int, int) {
fn (mut bmp BitMap) draw_glyph(index u16) (int, int){
glyph := bmp.tf.read_glyph(index) glyph := bmp.tf.read_glyph(index)
if !glyph.valid_glyph { if !glyph.valid_glyph {
return 0, 0 return 0, 0
} }
@ -744,27 +713,27 @@ fn (mut bmp BitMap) draw_glyph(index u16) (int, int){
bmp.clear_filler() bmp.clear_filler()
} }
mut s := 0 // status mut s := 0 // status
mut c := 0 // contours count mut c := 0 // contours count
mut contour_start := 0 mut contour_start := 0
mut x0 := 0 mut x0 := 0
mut y0 := 0 mut y0 := 0
color := bmp.color //u32(0xFFFF_FF00) // RGBA white color := bmp.color // u32(0xFFFF_FF00) // RGBA white
//color1 := u32(0xFF00_0000) // RGBA red // color1 := u32(0xFF00_0000) // RGBA red
//color2 := u32(0x00FF_0000) // RGBA green // color2 := u32(0x00FF_0000) // RGBA green
mut sp_x := 0 mut sp_x := 0
mut sp_y := 0 mut sp_y := 0
mut point := Point{} mut point := Point{}
for count, point_raw in glyph.points { for count, point_raw in glyph.points {
//dprintln("count: $count, state: $s pl:$glyph.points.len") // dprintln("count: $count, state: $s pl:$glyph.points.len")
point.x = point_raw.x point.x = point_raw.x
point.y = point_raw.y point.y = point_raw.y
point.x , point.y = bmp.trf_ch(point) point.x, point.y = bmp.trf_ch(point)
point.on_curve = point_raw.on_curve point.on_curve = point_raw.on_curve
if s == 0 { if s == 0 {
x0 = point.x x0 = point.x
y0 = point.y y0 = point.y
@ -775,69 +744,67 @@ fn (mut bmp BitMap) draw_glyph(index u16) (int, int){
} else if s == 1 { } else if s == 1 {
if point.on_curve { if point.on_curve {
bmp.line(x0, y0, point.x, point.y, color) bmp.line(x0, y0, point.x, point.y, color)
//bmp.aline(x0, y0, point.x, point.y, u32(0xFFFF0000)) // bmp.aline(x0, y0, point.x, point.y, u32(0xFFFF0000))
x0 = point.x x0 = point.x
y0 = point.y y0 = point.y
} else { } else {
s = 2 s = 2
} }
} else { } else {
//dprintln("s==2") // dprintln("s==2")
mut prev := glyph.points[count - 1] mut prev := glyph.points[count - 1]
prev.x, prev.y = bmp.trf_ch(prev) prev.x, prev.y = bmp.trf_ch(prev)
if point.on_curve { if point.on_curve {
//dprintln("HERE1") // dprintln("HERE1")
// ctx.quadraticCurveTo(prev.x + x, prev.y + y,point.x + x, point.y + y); // ctx.quadraticCurveTo(prev.x + x, prev.y + y,point.x + x, point.y + y);
//bmp.line(x0, y0, point.x + in_x, point.y + in_y, color1) // bmp.line(x0, y0, point.x + in_x, point.y + in_y, color1)
//bmp.quadratic(x0, y0, point.x + in_x, point.y + in_y, prev.x + in_x, prev.y + in_y, u32(0xa0a00000)) // bmp.quadratic(x0, y0, point.x + in_x, point.y + in_y, prev.x + in_x, prev.y + in_y, u32(0xa0a00000))
bmp.quadratic(x0, y0, point.x, point.y, prev.x, prev.y, color) bmp.quadratic(x0, y0, point.x, point.y, prev.x, prev.y, color)
x0 = point.x x0 = point.x
y0 = point.y y0 = point.y
s = 1 s = 1
} else { } else {
//dprintln("HERE2") // dprintln("HERE2")
// ctx.quadraticCurveTo(prev.x + x, prev.y + y, // ctx.quadraticCurveTo(prev.x + x, prev.y + y,
// (prev.x + point.x) / 2 + x, // (prev.x + point.x) / 2 + x,
// (prev.y + point.y) / 2 + y); // (prev.y + point.y) / 2 + y);
//bmp.line(x0, y0, (prev.x + point.x)/2, (prev.y + point.y)/2, color2) // bmp.line(x0, y0, (prev.x + point.x)/2, (prev.y + point.y)/2, color2)
//bmp.quadratic(x0, y0, (prev.x + point.x)/2, (prev.y + point.y)/2, prev.x, prev.y, color2) // bmp.quadratic(x0, y0, (prev.x + point.x)/2, (prev.y + point.y)/2, prev.x, prev.y, color2)
bmp.quadratic(x0, y0, (prev.x + point.x)/2, (prev.y + point.y)/2, prev.x, prev.y, color) bmp.quadratic(x0, y0, (prev.x + point.x) / 2, (prev.y + point.y) / 2,
x0 = (prev.x + point.x)/2 prev.x, prev.y, color)
y0 = (prev.y + point.y)/2 x0 = (prev.x + point.x) / 2
y0 = (prev.y + point.y) / 2
} }
} }
if count == glyph.contour_ends[c] { if count == glyph.contour_ends[c] {
//dprintln("count == glyph.contour_ends[count]") // dprintln("count == glyph.contour_ends[count]")
if s == 2 { // final point was off-curve. connect to start if s == 2 { // final point was off-curve. connect to start
mut start_point := glyph.points[contour_start] mut start_point := glyph.points[contour_start]
start_point.x, start_point.y = bmp.trf_ch(start_point) start_point.x, start_point.y = bmp.trf_ch(start_point)
if point.on_curve { if point.on_curve {
//ctx.quadraticCurveTo(prev.x + x, prev.y + y, // ctx.quadraticCurveTo(prev.x + x, prev.y + y,
//point.x + x, point.y + y); // point.x + x, point.y + y);
//bmp.line(x0, y0, start_point.x + in_x, start_point.y + in_y, u32(0x00FF0000)) // bmp.line(x0, y0, start_point.x + in_x, start_point.y + in_y, u32(0x00FF0000))
bmp.quadratic(x0, y0, start_point.x, start_point.y ,
// start_point.x + in_x, start_point.y + in_y, u32(0xFF00FF00)) // start_point.x + in_x, start_point.y + in_y, u32(0xFF00FF00))
start_point.x, start_point.y, color) bmp.quadratic(x0, y0, start_point.x, start_point.y, start_point.x,
start_point.y, color)
} else { } else {
//ctx.quadraticCurveTo(prev.x + x, prev.y + y, // ctx.quadraticCurveTo(prev.x + x, prev.y + y,
// (prev.x + point.x) / 2 + x, // (prev.x + point.x) / 2 + x,
// (prev.y + point.y) / 2 + y); // (prev.y + point.y) / 2 + y);
//bmp.line(x0, y0, start_point.x, start_point.y, u32(0x00FF0000) // bmp.line(x0, y0, start_point.x, start_point.y, u32(0x00FF0000)
bmp.quadratic(x0, y0, start_point.x, start_point.y, // u32(0xFF000000))
(point.x + start_point.x)/2, bmp.quadratic(x0, y0, start_point.x, start_point.y, (point.x +
(point.y + start_point.y)/2, start_point.x) / 2, (point.y + start_point.y) / 2, color)
//u32(0xFF000000))
color)
} }
} else { } else {
// last point not in a curve // last point not in a curve
//bmp.line(point.x, point.y, sp_x, sp_y, u32(0x00FF0000)) // bmp.line(point.x, point.y, sp_x, sp_y, u32(0x00FF0000))
bmp.line(point.x, point.y, sp_x, sp_y, color) bmp.line(point.x, point.y, sp_x, sp_y, color)
} }
contour_start = count + 1 contour_start = count + 1
@ -852,6 +819,6 @@ fn (mut bmp BitMap) draw_glyph(index u16) (int, int){
x_min := glyph.x_min x_min := glyph.x_min
x_max := glyph.x_max x_max := glyph.x_max
return x_min, x_max return x_min, x_max
//return glyph.x_min, glyph.x_max // return glyph.x_min, glyph.x_max
} }

View File

@ -1,4 +1,5 @@
module ttf module ttf
/********************************************************************** /**********************************************************************
* *
* BMP render module utility functions * BMP render module utility functions
@ -15,15 +16,13 @@ import math
import gg import gg
import sokol.sgl import sokol.sgl
pub pub struct TTF_render_Sokol {
struct TTF_render_Sokol {
pub mut: pub mut:
bmp &BitMap // Base bitmap render bmp &BitMap // Base bitmap render
// rendering fields // rendering fields
sg_img C.sg_image // sokol image sg_img C.sg_image // sokol image
scale_reduct f32 = 2.0 // scale of the cpu texture for filtering scale_reduct f32 = 2.0 // scale of the cpu texture for filtering
device_dpi int = 72 // device DPI device_dpi int = 72 // device DPI
} }
/****************************************************************************** /******************************************************************************
@ -31,93 +30,91 @@ pub mut:
* Render functions * Render functions
* *
******************************************************************************/ ******************************************************************************/
fn (mut tf_skl TTF_render_Sokol) format_texture(){ fn (mut tf_skl TTF_render_Sokol) format_texture() {
tf_skl.bmp.format_texture() tf_skl.bmp.format_texture()
} }
pub pub fn (mut tf_skl TTF_render_Sokol) create_text(in_txt string, in_font_size f32) {
fn (mut tf_skl TTF_render_Sokol) create_text(in_txt string, in_font_size f32){
scale_reduct := tf_skl.scale_reduct scale_reduct := tf_skl.scale_reduct
device_dpi := tf_skl.device_dpi device_dpi := tf_skl.device_dpi
font_size := in_font_size //* scale_reduct font_size := in_font_size //* scale_reduct
// Formula: (font_size * device dpi) / (72dpi * em_unit) // Formula: (font_size * device dpi) / (72dpi * em_unit)
//scale := ((1.0 * devide_dpi )/ f32(72 * tf_skl.bmp.tf.units_per_em))* font_size // scale := ((1.0 * devide_dpi )/ f32(72 * tf_skl.bmp.tf.units_per_em))* font_size
scale := f32(font_size * device_dpi) / f32(72 * tf_skl.bmp.tf.units_per_em) scale := f32(font_size * device_dpi) / f32(72 * tf_skl.bmp.tf.units_per_em)
//dprintln("Scale: $scale") // dprintln("Scale: $scale")
tf_skl.bmp.scale = scale * scale_reduct tf_skl.bmp.scale = scale * scale_reduct
w, h := tf_skl.bmp.get_bbox(in_txt) w, h := tf_skl.bmp.get_bbox(in_txt)
tf_skl.bmp.width = int(w) tf_skl.bmp.width = int(w)
tf_skl.bmp.height = int((h+8)) tf_skl.bmp.height = int((h + 8))
sz := tf_skl.bmp.width * tf_skl.bmp.height * tf_skl.bmp.bp sz := tf_skl.bmp.width * tf_skl.bmp.height * tf_skl.bmp.bp
// RAM buffer // RAM buffer
if sz > tf_skl.bmp.buf_size { if sz > tf_skl.bmp.buf_size {
if sz > 0 { if sz > 0 {
free(tf_skl.bmp.buf) free(tf_skl.bmp.buf)
} }
dprintln("create_text Alloc: $sz bytes") dprintln('create_text Alloc: $sz bytes')
tf_skl.bmp.buf = malloc(sz) tf_skl.bmp.buf = malloc(sz)
tf_skl.bmp.buf_size = sz tf_skl.bmp.buf_size = sz
} }
tf_skl.bmp.init_filler() tf_skl.bmp.init_filler()
// draw the text // draw the text
mut y_base := int((tf_skl.bmp.tf.y_max - tf_skl.bmp.tf.y_min) * tf_skl.bmp.scale) mut y_base := int((tf_skl.bmp.tf.y_max - tf_skl.bmp.tf.y_min) * tf_skl.bmp.scale)
tf_skl.bmp.set_pos(0,y_base) tf_skl.bmp.set_pos(0, y_base)
tf_skl.bmp.clear() tf_skl.bmp.clear()
tf_skl.bmp.draw_text(in_txt) tf_skl.bmp.draw_text(in_txt)
tf_skl.format_texture() tf_skl.format_texture()
} }
pub pub fn (mut tf_skl TTF_render_Sokol) create_text_block(in_txt string, in_w int, in_h int, in_font_size f32) {
fn (mut tf_skl TTF_render_Sokol) create_text_block(in_txt string, in_w int, in_h int, in_font_size f32){
scale_reduct := tf_skl.scale_reduct scale_reduct := tf_skl.scale_reduct
device_dpi := tf_skl.device_dpi device_dpi := tf_skl.device_dpi
font_size := in_font_size //* scale_reduct font_size := in_font_size //* scale_reduct
// Formula: (font_size * device dpi) / (72dpi * em_unit) // Formula: (font_size * device dpi) / (72dpi * em_unit)
//scale := ((1.0 * devide_dpi )/ f32(72 * tf_skl.bmp.tf.units_per_em))* font_size // scale := ((1.0 * devide_dpi )/ f32(72 * tf_skl.bmp.tf.units_per_em))* font_size
scale := f32(font_size * device_dpi) / f32(72 * tf_skl.bmp.tf.units_per_em) scale := f32(font_size * device_dpi) / f32(72 * tf_skl.bmp.tf.units_per_em)
//dprintln("Scale: $scale") // dprintln("Scale: $scale")
tf_skl.bmp.scale = scale * scale_reduct tf_skl.bmp.scale = scale * scale_reduct
w := in_w w := in_w
h := in_h h := in_h
tf_skl.bmp.width = int(w * scale_reduct + 0.5) tf_skl.bmp.width = int(w * scale_reduct + 0.5)
tf_skl.bmp.height = int((h+2) * scale_reduct + 0.5) tf_skl.bmp.height = int((h + 2) * scale_reduct + 0.5)
sz := tf_skl.bmp.width * tf_skl.bmp.height * tf_skl.bmp.bp sz := tf_skl.bmp.width * tf_skl.bmp.height * tf_skl.bmp.bp
//if true { return } // if true { return }
// RAM buffer // RAM buffer
if sz > tf_skl.bmp.buf_size { if sz > tf_skl.bmp.buf_size {
if sz > 0 { if sz > 0 {
free(tf_skl.bmp.buf) free(tf_skl.bmp.buf)
} }
dprintln("Alloc: $sz bytes") dprintln('Alloc: $sz bytes')
tf_skl.bmp.buf = malloc(sz) tf_skl.bmp.buf = malloc(sz)
tf_skl.bmp.buf_size = sz tf_skl.bmp.buf_size = sz
} }
tf_skl.bmp.init_filler() tf_skl.bmp.init_filler()
// draw the text // draw the text
mut y_base := int((tf_skl.bmp.tf.y_max - tf_skl.bmp.tf.y_min) * tf_skl.bmp.scale) mut y_base := int((tf_skl.bmp.tf.y_max - tf_skl.bmp.tf.y_min) * tf_skl.bmp.scale)
tf_skl.bmp.set_pos(0,y_base) tf_skl.bmp.set_pos(0, y_base)
tf_skl.bmp.clear() tf_skl.bmp.clear()
tf_skl.bmp.draw_text_block(in_txt, {x: 0, y:0, w:w, h:h}) tf_skl.bmp.draw_text_block(in_txt, x: 0, y: 0, w: w, h: h)
tf_skl.format_texture() tf_skl.format_texture()
} }
/****************************************************************************** /******************************************************************************
* *
* Sokol Render functions * Sokol Render functions
* *
******************************************************************************/ ******************************************************************************/
pub pub fn (mut tf_skl TTF_render_Sokol) create_texture() {
fn (mut tf_skl TTF_render_Sokol) create_texture(){
w := tf_skl.bmp.width w := tf_skl.bmp.width
h := tf_skl.bmp.height h := tf_skl.bmp.height
sz := tf_skl.bmp.width * tf_skl.bmp.height * tf_skl.bmp.bp sz := tf_skl.bmp.width * tf_skl.bmp.height * tf_skl.bmp.bp
@ -125,9 +122,9 @@ fn (mut tf_skl TTF_render_Sokol) create_texture(){
width: w width: w
height: h height: h
num_mipmaps: 0 num_mipmaps: 0
min_filter: .linear min_filter: .linear
mag_filter: .linear mag_filter: .linear
//usage: .dynamic // usage: .dynamic
wrap_u: .clamp_to_edge wrap_u: .clamp_to_edge
wrap_v: .clamp_to_edge wrap_v: .clamp_to_edge
label: &byte(0) label: &byte(0)
@ -138,38 +135,35 @@ fn (mut tf_skl TTF_render_Sokol) create_texture(){
ptr: tf_skl.bmp.buf ptr: tf_skl.bmp.buf
size: sz size: sz
} }
simg := C.sg_make_image(&img_desc) simg := C.sg_make_image(&img_desc)
//free(tf_skl.bmp.buf) // DONT FREE IF Dynamic // free(tf_skl.bmp.buf) // DONT FREE IF Dynamic
tf_skl.sg_img = simg tf_skl.sg_img = simg
} }
pub pub fn (tf_skl TTF_render_Sokol) destroy_texture() {
fn (tf_skl TTF_render_Sokol) destroy_texture(){
C.sg_destroy_image(tf_skl.sg_img) C.sg_destroy_image(tf_skl.sg_img)
} }
// Use only if usage: .dynamic // Use only if usage: .dynamic
pub pub fn (mut tf_skl TTF_render_Sokol) update_text_texture() {
fn (mut tf_skl TTF_render_Sokol) update_text_texture(){
sz := tf_skl.bmp.width * tf_skl.bmp.height * tf_skl.bmp.bp sz := tf_skl.bmp.width * tf_skl.bmp.height * tf_skl.bmp.bp
mut tmp_sbc := C.sg_image_content{} mut tmp_sbc := C.sg_image_content{}
tmp_sbc.subimage[0][0] = C.sg_subimage_content { tmp_sbc.subimage[0][0] = C.sg_subimage_content{
ptr: tf_skl.bmp.buf ptr: tf_skl.bmp.buf
size: sz size: sz
} }
C.sg_update_image(tf_skl.sg_img, &tmp_sbc) C.sg_update_image(tf_skl.sg_img, &tmp_sbc)
} }
pub pub fn (tf_skl TTF_render_Sokol) draw_text_bmp(ctx &gg.Context, x f32, y f32) {
fn (tf_skl TTF_render_Sokol) draw_text_bmp(ctx &gg.Context, x f32, y f32) { // width := tf_skl.bmp.width >> 1
//width := tf_skl.bmp.width >> 1 // height := tf_skl.bmp.height >> 1
//height := tf_skl.bmp.height >> 1
sgl.push_matrix() sgl.push_matrix()
width := tf_skl.bmp.width / (tf_skl.scale_reduct) width := tf_skl.bmp.width / (tf_skl.scale_reduct)
height := tf_skl.bmp.height / (tf_skl.scale_reduct) height := tf_skl.bmp.height / (tf_skl.scale_reduct)
u0 := f32(0.0) u0 := f32(0.0)
v0 := f32(0.0) v0 := f32(0.0)
u1 := f32(1.0) u1 := f32(1.0)
@ -182,10 +176,22 @@ fn (tf_skl TTF_render_Sokol) draw_text_bmp(ctx &gg.Context, x f32, y f32) {
ca := f32(math.cos(tf_skl.bmp.angle)) ca := f32(math.cos(tf_skl.bmp.angle))
sa := f32(math.sin(tf_skl.bmp.angle)) sa := f32(math.sin(tf_skl.bmp.angle))
m := [ m := [
f32(ca),-sa,0,0, f32(ca),
sa,ca,0,0, -sa,
0,0,1,0, 0,
x,y,0,1 0,
sa,
ca,
0,
0,
0,
0,
1,
0,
x,
y,
0,
1,
] ]
sgl.mult_matrix(m) sgl.mult_matrix(m)
// //

View File

@ -1,4 +1,5 @@
module ttf module ttf
/********************************************************************** /**********************************************************************
* *
* BMP render module utility functions * BMP render module utility functions
@ -11,40 +12,38 @@ module ttf
* *
* TODO: * TODO:
**********************************************************************/ **********************************************************************/
pub pub struct Text_block {
struct Text_block { x int // x postion of the left high corner
x int // x postion of the left high corner y int // y postion of the left high corner
y int // y postion of the left high corner w int // width of the text block
w int // width of the text block h int // heigth of the text block
h int // heigth of the text block cut_lines bool = true // force to cut the line if the length is over the text block width
cut_lines bool = true // force to cut the line if the length is over the text block width
} }
fn (mut dev BitMap) get_justify_space_cw(txt string, w int, block_w int, space_cw int) f32 { fn (mut dev BitMap) get_justify_space_cw(txt string, w int, block_w int, space_cw int) f32 {
num_spaces := txt.count(" ") num_spaces := txt.count(' ')
if num_spaces < 1 { if num_spaces < 1 {
return 0 return 0
} }
delta := block_w - w delta := block_w - w
//println("num spc: $num_spaces") // println("num spc: $num_spaces")
//println("delta: ${txt} w:$w bw:$block_w space_cw:$space_cw") // println("delta: ${txt} w:$w bw:$block_w space_cw:$space_cw")
res := f32(delta)/f32(num_spaces)/f32(space_cw) res := f32(delta) / f32(num_spaces) / f32(space_cw)
//println("res: $res") // println("res: $res")
return res return res
} }
// write out a text // write out a text
pub pub fn (mut bmp BitMap) draw_text_block(text string, block Text_block) {
fn (mut bmp BitMap) draw_text_block(text string, block Text_block) {
mut x := block.x mut x := block.x
mut y := block.y mut y := block.y
mut y_base := int((bmp.tf.y_max - bmp.tf.y_min) * bmp.scale) mut y_base := int((bmp.tf.y_max - bmp.tf.y_min) * bmp.scale)
//bmp.box(x, y, x + block.w, y + block.h, u32(0xFF00_0000)) // bmp.box(x, y, x + block.w, y + block.h, u32(0xFF00_0000))
// spaces data // spaces data
mut space_cw, _ := bmp.tf.get_horizontal_metrics(u16(` `)) mut space_cw, _ := bmp.tf.get_horizontal_metrics(u16(` `))
space_cw = int(space_cw * bmp.scale) space_cw = int(space_cw * bmp.scale)
old_space_cw := bmp.space_cw old_space_cw := bmp.space_cw
@ -57,40 +56,40 @@ fn (mut bmp BitMap) draw_text_block(text string, block Text_block) {
for txt in text.split_into_lines() { for txt in text.split_into_lines() {
bmp.space_cw = old_space_cw bmp.space_cw = old_space_cw
mut w,mut h := bmp.get_bbox(txt) mut w, mut h := bmp.get_bbox(txt)
if w <= block.w || block.cut_lines == false { if w <= block.w || block.cut_lines == false {
//println("Solid block!") // println("Solid block!")
left_offset := int((block.w - w) * offset_flag) left_offset := int((block.w - w) * offset_flag)
if bmp.justify && (f32(w) / f32(block.w)) >= bmp.justify_fill_ratio { if bmp.justify && (f32(w) / f32(block.w)) >= bmp.justify_fill_ratio {
bmp.space_cw = old_space_cw + bmp.get_justify_space_cw(txt, w, block.w, space_cw) bmp.space_cw = old_space_cw + bmp.get_justify_space_cw(txt, w, block.w, space_cw)
} }
bmp.set_pos(x + left_offset ,y + y_base) bmp.set_pos(x + left_offset, y + y_base)
bmp.draw_text(txt) bmp.draw_text(txt)
//---- DEBUG ---- //---- DEBUG ----
//mut txt_w , mut txt_h := bmp.draw_text(txt) // mut txt_w , mut txt_h := bmp.draw_text(txt)
//bmp.box(x + left_offset,y+y_base - int((bmp.tf.y_min)*bmp.scale), x + txt_w + left_offset, y + y_base - int((bmp.tf.y_max) * bmp.scale), u32(0x00ff_0000) ) // bmp.box(x + left_offset,y+y_base - int((bmp.tf.y_min)*bmp.scale), x + txt_w + left_offset, y + y_base - int((bmp.tf.y_max) * bmp.scale), u32(0x00ff_0000) )
//--------------- //---------------
y += y_base y += y_base
} else { } else {
//println("to cut: ${txt}") // println("to cut: ${txt}")
mut txt1 := txt.split(" ") mut txt1 := txt.split(' ')
mut c:= txt1.len mut c := txt1.len
//mut done := false // mut done := false
for c > 0 { for c > 0 {
tmp_str := txt1[0..c].join(' ') tmp_str := txt1[0..c].join(' ')
//println("tmp_str: ${tmp_str}") // println("tmp_str: ${tmp_str}")
if tmp_str.len < 1 { if tmp_str.len < 1 {
break break
} }
bmp.space_cw = old_space_cw bmp.space_cw = old_space_cw
w,h = bmp.get_bbox(tmp_str) w, h = bmp.get_bbox(tmp_str)
if w <= block.w { if w <= block.w {
mut left_offset := int((block.w - w) * offset_flag) mut left_offset := int((block.w - w) * offset_flag)
if bmp.justify && (f32(w) / f32(block.w)) >= bmp.justify_fill_ratio { if bmp.justify && (f32(w) / f32(block.w)) >= bmp.justify_fill_ratio {
//println("cut phase!") // println("cut phase!")
bmp.space_cw = 0.0 bmp.space_cw = 0.0
w,h = bmp.get_bbox(tmp_str) w, h = bmp.get_bbox(tmp_str)
left_offset = int((block.w - w) * offset_flag) left_offset = int((block.w - w) * offset_flag)
bmp.space_cw = bmp.get_justify_space_cw(tmp_str, w, block.w, space_cw) bmp.space_cw = bmp.get_justify_space_cw(tmp_str, w, block.w, space_cw)
} else { } else {
@ -99,16 +98,16 @@ fn (mut bmp BitMap) draw_text_block(text string, block Text_block) {
bmp.set_pos(x + left_offset, y + y_base) bmp.set_pos(x + left_offset, y + y_base)
bmp.draw_text(tmp_str) bmp.draw_text(tmp_str)
//---- DEBUG ---- //---- DEBUG ----
//txt_w , txt_h := bmp.draw_text(tmp_str) // txt_w , txt_h := bmp.draw_text(tmp_str)
//println("printing [${x},${y}] => '${tmp_str}' space_cw: $bmp.space_cw") // println("printing [${x},${y}] => '${tmp_str}' space_cw: $bmp.space_cw")
//bmp.box(x + left_offset,y + y_base - int((bmp.tf.y_min)*bmp.scale), x + txt_w + left_offset, y + y_base - int((bmp.tf.y_max) * bmp.scale), u32(0x00ff_0000) ) // bmp.box(x + left_offset,y + y_base - int((bmp.tf.y_min)*bmp.scale), x + txt_w + left_offset, y + y_base - int((bmp.tf.y_max) * bmp.scale), u32(0x00ff_0000) )
//--------------- //---------------
y += y_base y += y_base
txt1 = txt1[c..] txt1 = txt1[c..]
c= txt1.len c = txt1.len
//---- DEBUG ---- //---- DEBUG ----
//txt2 := txt1.join(' ') // txt2 := txt1.join(' ')
//println("new string: ${txt2} len: ${c}") // println("new string: ${txt2} len: ${c}")
//--------------- //---------------
} else { } else {
c-- c--

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -171,21 +171,27 @@ fn (mut ws Client) send_message_event(msg &Message) {
ws.debug_log('sending on_message event') ws.debug_log('sending on_message event')
for ev_handler in ws.message_callbacks { for ev_handler in ws.message_callbacks {
if !ev_handler.is_ref { if !ev_handler.is_ref {
ev_handler.handler(ws, msg) ev_handler.handler(ws, msg) or { ws.logger.error('send_message_event error: $err') }
} else { } else {
ev_handler.handler2(ws, msg, ev_handler.ref) ev_handler.handler2(ws, msg, ev_handler.ref) or {
ws.logger.error('send_message_event error: $err')
}
} }
} }
} }
// send_error_event invokes the on_error callback // send_error_event invokes the on_error callback
fn (mut ws Client) send_error_event(err string) { fn (mut ws Client) send_error_event(error string) {
ws.debug_log('sending on_error event') ws.debug_log('sending on_error event')
for ev_handler in ws.error_callbacks { for ev_handler in ws.error_callbacks {
if !ev_handler.is_ref { if !ev_handler.is_ref {
ev_handler.handler(mut ws, err) ev_handler.handler(mut ws, error) or {
ws.logger.error('send_error_event error: $error, err: $err')
}
} else { } else {
ev_handler.handler2(mut ws, err, ev_handler.ref) ev_handler.handler2(mut ws, error, ev_handler.ref) or {
ws.logger.error('send_error_event error: $error, err: $err')
}
} }
} }
} }
@ -195,9 +201,13 @@ fn (mut ws Client) send_close_event(code int, reason string) {
ws.debug_log('sending on_close event') ws.debug_log('sending on_close event')
for ev_handler in ws.close_callbacks { for ev_handler in ws.close_callbacks {
if !ev_handler.is_ref { if !ev_handler.is_ref {
ev_handler.handler(mut ws, code, reason) ev_handler.handler(mut ws, code, reason) or {
ws.logger.error('send_close_event error: $err')
}
} else { } else {
ev_handler.handler2(mut ws, code, reason, ev_handler.ref) ev_handler.handler2(mut ws, code, reason, ev_handler.ref) or {
ws.logger.error('send_close_event error: $err')
}
} }
} }
} }
@ -207,9 +217,11 @@ fn (mut ws Client) send_open_event() {
ws.debug_log('sending on_open event') ws.debug_log('sending on_open event')
for ev_handler in ws.open_callbacks { for ev_handler in ws.open_callbacks {
if !ev_handler.is_ref { if !ev_handler.is_ref {
ev_handler.handler(mut ws) ev_handler.handler(mut ws) or { ws.logger.error('send_open_event error: $err') }
} else { } else {
ev_handler.handler2(mut ws, ev_handler.ref) ev_handler.handler2(mut ws, ev_handler.ref) or {
ws.logger.error('send_open_event error: $err')
}
} }
} }
} }

View File

@ -39,7 +39,7 @@ const (
// validate_client validates client frame rules from RFC6455 // validate_client validates client frame rules from RFC6455
pub fn (mut ws Client) validate_frame(frame &Frame) ? { pub fn (mut ws Client) validate_frame(frame &Frame) ? {
if frame.rsv1 || frame.rsv2 || frame.rsv3 { if frame.rsv1 || frame.rsv2 || frame.rsv3 {
ws.close(1002, 'rsv cannot be other than 0, not negotiated') ws.close(1002, 'rsv cannot be other than 0, not negotiated') ?
return error('rsv cannot be other than 0, not negotiated') return error('rsv cannot be other than 0, not negotiated')
} }
if (int(frame.opcode) >= 3 && int(frame.opcode) <= 7) if (int(frame.opcode) >= 3 && int(frame.opcode) <= 7)
@ -113,7 +113,7 @@ fn (mut ws Client) validate_utf_8(opcode OPCode, payload []byte) ? {
if opcode in [.text_frame, .close] && !utf8.validate(payload.data, payload.len) { if opcode in [.text_frame, .close] && !utf8.validate(payload.data, payload.len) {
ws.logger.error('malformed utf8 payload, payload len: ($payload.len)') ws.logger.error('malformed utf8 payload, payload len: ($payload.len)')
ws.send_error_event('Recieved malformed utf8.') ws.send_error_event('Recieved malformed utf8.')
ws.close(1007, 'malformed utf8 payload') ws.close(1007, 'malformed utf8 payload') ?
return error('malformed utf8 payload') return error('malformed utf8 payload')
} }
} }

View File

@ -111,7 +111,7 @@ pub fn (mut ws Client) listen() ? {
defer { defer {
ws.logger.info('Quit client listener, server($ws.is_server)...') ws.logger.info('Quit client listener, server($ws.is_server)...')
if ws.state == .open { if ws.state == .open {
ws.close(1000, 'closed by client') ws.close(1000, 'closed by client') or { }
} }
} }
for ws.state == .open { for ws.state == .open {
@ -243,10 +243,6 @@ pub fn (mut ws Client) write_ptr(bytes byteptr, payload_len int, code OPCode) ?
mut header := []byte{len: header_len, init: `0`} // [`0`].repeat(header_len) mut header := []byte{len: header_len, init: `0`} // [`0`].repeat(header_len)
header[0] = byte(int(code)) | 0x80 header[0] = byte(int(code)) | 0x80
masking_key := create_masking_key() masking_key := create_masking_key()
defer {
unsafe {
}
}
if ws.is_server { if ws.is_server {
if payload_len <= 125 { if payload_len <= 125 {
header[1] = byte(payload_len) header[1] = byte(payload_len)
@ -315,7 +311,7 @@ pub fn (mut ws Client) write(bytes []byte, code OPCode) ? {
// write_str, writes a string with a websocket texttype to socket // write_str, writes a string with a websocket texttype to socket
pub fn (mut ws Client) write_str(str string) ? { pub fn (mut ws Client) write_str(str string) ? {
ws.write_ptr(str.str, str.len, .text_frame) ws.write_ptr(str.str, str.len, .text_frame) ?
} }
// close closes the websocket connection // close closes the websocket connection
@ -328,7 +324,7 @@ pub fn (mut ws Client) close(code int, message string) ? {
return ret_err return ret_err
} }
defer { defer {
ws.shutdown_socket() ws.shutdown_socket() or { }
ws.reset_state() ws.reset_state()
} }
ws.set_state(.closing) ws.set_state(.closing)

View File

@ -30,7 +30,7 @@ fn start_server() ? {
}) ? }) ?
s.on_message(fn (mut ws websocket.Client, msg &websocket.Message) ? { s.on_message(fn (mut ws websocket.Client, msg &websocket.Message) ? {
match msg.opcode { match msg.opcode {
.pong { ws.write_str('pong') } .pong { ws.write_str('pong') or { panic(err) } }
else { ws.write(msg.payload, msg.opcode) or { panic(err) } } else { ws.write(msg.payload, msg.opcode) or { panic(err) } }
} }
}) })