From 1ae38e8445429a2a9922a751dfb01163afa89ee2 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Wed, 6 Nov 2024 22:19:35 +0300 Subject: [PATCH] json config; fix decrease font; save font size; better cur_fn placement; ~ for home in file path --- TODO.txt | 2 +- config.v | 171 +++++++++++++++++++++++--------------------- ved.v | 211 +++++++++++++++++++++++++++++++------------------------ view.v | 12 ++-- 4 files changed, 220 insertions(+), 176 deletions(-) diff --git a/TODO.txt b/TODO.txt index 046ff78..6076cc6 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,4 +1,4 @@ -- list of all open files (similar to ctrl p) ++ list of all open files (similar to ctrl p) - use ui.textbox - print error message on the actual line - remember line pos for each file on t diff --git a/config.v b/config.v index 31437ba..b430581 100644 --- a/config.v +++ b/config.v @@ -5,7 +5,7 @@ module main import os import gx -import toml +// import toml import json // The different kinds of cursors @@ -19,16 +19,16 @@ enum Cursor { // TODO: Load user config from file struct Config { mut: - settings toml.Doc + // settings toml.Doc dark_mode bool cursor_style Cursor - text_size int - line_height int - char_width int - tab_size int - tab int + text_size int = min_text_size + line_height int = 20 + char_width int = 8 + tab_size int = 4 + tab int = int(`\t`) // TODO read from config file? backspace_go_up bool - vcolor gx.Color + vcolor gx.Color // v selection background color split_color gx.Color bgcolor gx.Color // base00 errorbgcolor gx.Color // base08 @@ -56,25 +56,39 @@ mut: green_cfg gx.TextCfg red_color gx.Color // base08 red_cfg gx.TextCfg - disable_mouse bool - disable_fmt bool + disable_mouse bool = true + // Config.json + disable_fmt bool } +/* +// json +struct Config2 { + disable_fmt bool + text_size int + line_height int + char_width int +} +*/ + +/* fn (mut config Config) set_settings(path string) { config.settings = toml.parse_file(path) or { toml.parse_text('') or { panic(err) } } } +*/ // reload_config reloads the config from config.toml file -fn (mut config Config) reload_config() { +// set_default_color_values? +fn (mut config Config) set_default_values() { config.init_colors() config.set_cursor_style() - config.set_text_size() - config.set_line_height() - config.set_char_width() - config.set_tab() - config.set_backspace_behaviour() - config.set_disable_mouse() + // config.set_text_size() + // config.set_line_height() + // config.set_char_width() + // config.set_tab() + // config.set_backspace_behaviour() + // config.set_disable_mouse() config.set_vcolor() config.set_split() config.set_bgcolor() @@ -95,11 +109,11 @@ fn (mut config Config) reload_config() { } fn (mut config Config) init_colors() { - toml_dark_mode := config.settings.value('editor.dark_mode').bool() - config.dark_mode = toml_dark_mode || '-dark' in os.args + config.dark_mode ||= '-dark' in os.args } fn (mut config Config) set_cursor_style() { + /* toml_cursor_style := config.settings.value('editor.cursor').string() if toml_cursor_style != 'toml.Any(toml.Null{})' { match toml_cursor_style { @@ -110,44 +124,14 @@ fn (mut config Config) set_cursor_style() { } return } + */ config.cursor_style = .block } -fn (mut config Config) set_text_size() { - toml_text_size := config.settings.value('editor.text_size').int() - config.text_size = if toml_text_size > 0 { toml_text_size } else { 18 } -} - -fn (mut config Config) set_line_height() { - toml_line_height := config.settings.value('editor.line_height').int() - config.line_height = if toml_line_height > 0 { toml_line_height } else { 20 } -} - -fn (mut config Config) set_char_width() { - toml_char_width := config.settings.value('editor.char_width').int() - config.char_width = if toml_char_width > 0 { toml_char_width } else { 8 } -} - -fn (mut config Config) set_tab() { - toml_tab_size := config.settings.value('editor.tab_size').int() - config.tab_size = if toml_tab_size > 0 { toml_tab_size } else { 4 } - - // TODO: read this in from the config file - config.tab = int(`\t`) -} - -fn (mut config Config) set_backspace_behaviour() { - toml_backspace_behaviour := config.settings.value('editor.backspace_go_up').bool() - config.backspace_go_up = toml_backspace_behaviour -} - -fn (mut config Config) set_disable_mouse() { - config.disable_mouse = config.settings.value('editor.disable_mouse').bool() - config.disable_mouse = true // TODO remove once mouse bugs are fixed -} - // Convert a toml key color (in hex) to a gx.Color type +/* fn (config Config) get_toml_color(base string) !gx.Color { + toml_hex := config.settings.value('colors.base${base}').string() if toml_hex != 'toml.Any(toml.Null{})' { toml_red := ('0x' + toml_hex[0..2]).u8() @@ -159,6 +143,7 @@ fn (config Config) get_toml_color(base string) !gx.Color { return error('Couldn\'t read base${base} from the settings file') } +*/ fn (mut config Config) set_vcolor() { if !config.dark_mode { @@ -178,24 +163,25 @@ fn (mut config Config) set_split() { // base 00 fn (mut config Config) set_bgcolor() { - config.bgcolor = config.get_toml_color('00') or { - if config.dark_mode { - gx.rgb(30, 30, 30) - } else { - gx.rgb(245, 245, 245) - } + // config.bgcolor = config.get_toml_color('00') or { + config.bgcolor = if config.dark_mode { + gx.rgb(30, 30, 30) + } else { + gx.rgb(245, 245, 245) } + //} } // base 01 fn (mut config Config) set_errorbgcolor() { - config.errorbgcolor = config.get_toml_color('01') or { gx.rgb(240, 0, 0) } + // config.errorbgcolor = config.get_toml_color('01') or { gx.rgb(240, 0, 0) } + config.errorbgcolor = gx.rgb(240, 0, 0) } // base 0B fn (mut config Config) set_string() { - config.string_color = config.get_toml_color('0B') or { gx.rgb(179, 58, 44) } - + // config.string_color = config.get_toml_color('0B') or { gx.rgb(179, 58, 44) } + config.string_color = gx.rgb(179, 58, 44) config.string_cfg = gx.TextCfg{ size: config.text_size color: config.string_color @@ -204,7 +190,8 @@ fn (mut config Config) set_string() { // base 0E fn (mut config Config) set_key() { - config.key_color = config.get_toml_color('0E') or { gx.rgb(74, 103, 154) } + // config.key_color = config.get_toml_color('0E') or { gx.rgb(74, 103, 154) } + config.key_color = gx.rgb(74, 103, 154) config.key_cfg = gx.TextCfg{ size: config.text_size @@ -214,7 +201,8 @@ fn (mut config Config) set_key() { // base 0F fn (mut config Config) set_lit() { - config.lit_color = config.get_toml_color('0F') or { gx.rgb(7, 103, 154) } + // config.lit_color = config.get_toml_color('0F') or { gx.rgb(7, 103, 154) } + config.lit_color = gx.rgb(7, 103, 154) config.lit_cfg = gx.TextCfg{ size: config.text_size @@ -225,28 +213,27 @@ fn (mut config Config) set_lit() { // base 04 fn (mut config Config) set_title() { // config.title_color = config.get_toml_color('04') or { gx.rgb(40, 40, 40) } - config.title_color = config.get_toml_color('04') or { gx.rgb(0, 0, 0) } + config.title_color = gx.rgb(0, 0, 0) } // base 05 fn (mut config Config) set_cursor() { - config.cursor_color = config.get_toml_color('05') or { - if !config.dark_mode { - gx.black - } else { - gx.white - } + // config.cursor_color = config.get_toml_color('05') or { + config.cursor_color = if !config.dark_mode { + gx.black + } else { + gx.white } + //} } // base 05 (again) fn (mut config Config) set_txt() { - config.text_color = config.get_toml_color('05') or { - if !config.dark_mode { - gx.black - } else { - gx.rgb(212, 212, 212) - } + // config.text_color = config.get_toml_color('05') or { + config.text_color = if !config.dark_mode { + gx.black + } else { + gx.rgb(212, 212, 212) } config.txt_cfg = gx.TextCfg{ @@ -257,7 +244,8 @@ fn (mut config Config) set_txt() { // base 03 fn (mut config Config) set_comment() { - config.comment_color = config.get_toml_color('03') or { gx.dark_gray } + // config.comment_color = config.get_toml_color('03') or { gx.dark_gray } + config.comment_color = gx.dark_gray config.comment_cfg = gx.TextCfg{ size: config.text_size @@ -291,7 +279,8 @@ fn (mut config Config) set_minus() { // base 01 fn (mut config Config) set_line_nr() { - config.line_nr_color = config.get_toml_color('01') or { gx.dark_gray } + // config.line_nr_color = config.get_toml_color('01') or { gx.dark_gray } + config.line_nr_color = gx.dark_gray config.line_nr_cfg = gx.TextCfg{ size: config.text_size @@ -302,7 +291,8 @@ fn (mut config Config) set_line_nr() { // base 0B fn (mut config Config) set_green() { - config.green_color = config.get_toml_color('0B') or { gx.green } + // config.green_color = config.get_toml_color('0B') or { gx.green } + config.green_color = gx.green config.green_cfg = gx.TextCfg{ size: config.text_size @@ -311,7 +301,8 @@ fn (mut config Config) set_green() { } fn (mut config Config) set_red() { - config.red_color = config.get_toml_color('08') or { gx.red } + // config.red_color = config.get_toml_color('08') or { gx.red } + config.red_color = gx.red config.red_cfg = gx.TextCfg{ size: config.text_size color: config.red_color @@ -321,9 +312,29 @@ fn (mut config Config) set_red() { fn (mut ved Ved) load_config2() { if os.exists(config_path2) { if conf2 := json.decode(Config, os.read_file(config_path2) or { return }) { + println('AXAXAXAXA ${conf2}') + ved.cfg = conf2 + /* ved.cfg.disable_fmt = conf2.disable_fmt + ved.cfg.text_size = conf2.text_size + ved.cfg.line_height = conf2.line_height + ved.cfg.char_width = conf2.char_width + */ + // ved.cfg.disable_fmt = conf2.disable_fmt } else { println(err) } } } + +fn (mut ved Ved) save_config2() { + /* + config2 := Config2{ + text_size: ved.cfg.text_size + disable_fmt: ved.cfg.disable_fmt + line_height: ved.cfg.line_height + char_width: ved.cfg.char_width + } + */ + os.write_file(config_path2, json.encode_pretty(ved.cfg)) or { panic(err) } +} diff --git a/ved.v b/ved.v index d0541f0..5efec87 100644 --- a/ved.v +++ b/ved.v @@ -27,62 +27,61 @@ const max_nr_workspaces = 10 @[heap] struct Ved { mut: - win_width int - win_height int - nr_splits int - splits_per_workspace int - page_height int - views []View - cur_split int - view &View = unsafe { nil } - mode EditorMode - just_switched bool // for keydown/char events to avoid dup keys - prev_key gg.KeyCode - prev_key_str string // for `ci(` etc, no `(` in gg.KeyCode - prev_cmd string - prev_insert string // for `.` (re-enter the text that was just entered via cw etc) - all_git_files []string - top_tasks []string - gg &gg.Context = unsafe { nil } - query string - search_query string - query_type QueryType - workspace string - workspace_idx int - workspaces []string - ylines []string // for y, yy - git_diff_plus string // short git diff stat top right - git_diff_minus string - syntaxes []Syntax - current_syntax_idx int - chunks []Chunk - is_building bool - timer Timer - task_start_unix i64 - cur_task string - words []string - file_y_pos map[string]int // to save current line for each file s - refresh bool = true - char_width int - is_ml_comment bool - gg_lines []string - gg_pos int - cfg Config - cb &clipboard.Clipboard = unsafe { nil } - open_paths [][]string // all open files (tabs) per workspace: open_paths[workspace_idx] == ['a.txt', b.v'] - prev_y int // for jumping back ('') - now time.Time // cached value of time.now() to avoid calling it for every frame - search_history []string - search_idx int - cq_in_a_row int - search_dir string // for cmd+/ search in the entire directory where the current file is located - search_dir_idx int // for looping thru search dir files - error_line string // is displayed at the bottom - autocomplete_info AutocompleteInfo - autocomplete_cache map[string][]AutocompleteField // autocomplete_cache["v.checker.Checker"] == [{"AnonFn", "void"}, {"cur_anon_fn", "AnonFn"}] - debug_info string - debugger Debugger - cur_fn_name string // Always displayed on the top bar + win_width int + win_height int + nr_splits int + page_height int + views []View + cur_split int + view &View = unsafe { nil } + mode EditorMode + just_switched bool // for keydown/char events to avoid dup keys + prev_key gg.KeyCode + prev_key_str string // for `ci(` etc, no `(` in gg.KeyCode + prev_cmd string + prev_insert string // for `.` (re-enter the text that was just entered via cw etc) + all_git_files []string + top_tasks []string + gg &gg.Context = unsafe { nil } + query string + search_query string + query_type QueryType + workspace string + workspace_idx int + workspaces []string + ylines []string // for y, yy + git_diff_plus string // short git diff stat top right + git_diff_minus string + syntaxes []Syntax + current_syntax_idx int + chunks []Chunk + is_building bool + timer Timer + task_start_unix i64 + cur_task string + words []string + file_y_pos map[string]int // to save current line for each file s + refresh bool = true + char_width int + is_ml_comment bool + gg_lines []string + gg_pos int + cfg Config + cb &clipboard.Clipboard = unsafe { nil } + open_paths [][]string // all open files (tabs) per workspace: open_paths[workspace_idx] == ['a.txt', b.v'] + prev_y int // for jumping back ('') + now time.Time // cached value of time.now() to avoid calling it for every frame + search_history []string + search_idx int + cq_in_a_row int + search_dir string // for cmd+/ search in the entire directory where the current file is located + search_dir_idx int // for looping thru search dir files + error_line string // is displayed at the bottom + autocomplete_info AutocompleteInfo + autocomplete_cache map[string][]AutocompleteField // autocomplete_cache["v.checker.Checker"] == [{"AnonFn", "void"}, {"cur_anon_fn", "AnonFn"}] + debug_info string + debugger Debugger + cur_fn_name string // Always displayed on the top bar // debugger_output DebuggerOutput } @@ -147,7 +146,7 @@ fn main() { win_width: size.width win_height: size.height // nr_splits: nr_splits - // splits_per_workspace: nr_splits + // nr_splits: nr_splits cur_split: 0 mode: .normal cb: clipboard.new() @@ -155,14 +154,15 @@ fn main() { } ved.handle_segfault() + // ved.cfg.set_settings(config_path) + println('CONFIG') + println(ved.cfg) ved.load_config2() + ved.cfg.set_default_values() - ved.cfg.set_settings(config_path) - ved.cfg.reload_config() - - nr_splits := ved.get_nr_splits_from_screen_size(size.width, size.height) - ved.nr_splits = nr_splits - ved.splits_per_workspace = nr_splits + ved.nr_splits = ved.get_nr_splits_from_screen_size(size.width, size.height) + ved.calc_nr_splits_from_text_size() + println('splits per w = ${ved.nr_splits}') println('height=${size.height}') @@ -339,7 +339,7 @@ fn on_event(e &gg.Event, mut ved Ved) { } fn (ved &Ved) split_width() int { - mut split_width := ved.win_width / ved.nr_splits + 60 + mut split_width := ved.win_width / ved.nr_splits // + 60 if split_width < 300 { split_width = ved.win_width } @@ -396,7 +396,7 @@ fn (ved &Ved) calc_cursor_x() int { } cursor_tab_off++ } - from := ved.workspace_idx * ved.splits_per_workspace + from := ved.workspace_idx * ved.nr_splits split_width := ved.split_width() line_x := split_width * (ved.cur_split - from) + ved.view.padding_left + 10 mut cursor_x := line_x + (ved.view.x + cursor_tab_off * ved.cfg.tab_size) * ved.cfg.char_width @@ -482,7 +482,7 @@ fn (mut ved Ved) draw() { if ved.cur_task != '' { // Draw current task task_text_width := ved.cur_task.len * ved.cfg.char_width - task_x := ved.win_width - split_width - task_text_width - 10 + task_x := ved.win_width - split_width - task_text_width - 70 // ved.timer.gg.draw_text(task_x, 1, ved.timer.cur_task.to_upper(), file_name_cfg) ved.gg.draw_text(task_x, 1, ved.cur_task, ved.cfg.file_name_cfg) // Draw current task time @@ -493,9 +493,6 @@ fn (mut ved Ved) draw() { if ved.timer.pom_is_started { ved.gg.draw_text(split_width - 50, 1, '${ved.pomodoro_minutes()}m', ved.cfg.file_name_cfg) } - - // Cur fn name - ved.gg.draw_text(split_width - 600, 1, ved.cur_fn_name, ved.cfg.minus_cfg) // Draw "i" in insert mode if ved.mode == .insert { ved.gg.draw_text(5, 1, '-i-', ved.cfg.file_name_cfg) @@ -515,6 +512,18 @@ fn (mut ved Ved) draw() { ved.draw_split(i, from) // println('draw split $i: ${ glfw.get_time() - t }') } + // Cur fn name (top right of current split) + cur_fn_width := ved.cfg.char_width * ved.cur_fn_name.len + cur_fn_x := (ved.cur_split % ved.nr_splits + 1) * split_width - cur_fn_width - 3 + cur_fn_y := ved.cfg.line_height + ved.gg.draw_rect( + x: cur_fn_x + y: cur_fn_y + w: cur_fn_width + h: ved.cfg.line_height + color: ved.cfg.bgcolor // gx.rgb(40, 40, 40) + ) + ved.gg.draw_text(cur_fn_x, cur_fn_y, ved.cur_fn_name, ved.cfg.comment_cfg) // Debugger variables if ved.mode == .debugger && ved.debugger.output.vars.len > 0 { ved.draw_debugger_variables() @@ -667,6 +676,7 @@ fn (mut ved Ved) draw_text_line(x int, y int, line string, ext string) { // } else if line[0] == `-` { ved.chunks = [] cur_syntax := ved.syntaxes[ved.current_syntax_idx] or { Syntax{} } + // TODO use runes for everything to fix keyword + 2+ byte rune words for i := 0; i < line.len; i++ { start := i // Comment // # @@ -815,7 +825,6 @@ fn on_char(code u32, mut ved Ved) { ved.char_query(s) } .normal { - // on char on normal only for replace with r if !ved.just_switched && ved.prev_key == .r { if s != 'r' { @@ -955,7 +964,7 @@ fn (mut ved Ved) key_normal(key gg.KeyCode, mod gg.Modifier) { return } if ved.prev_cmd == 'ci' { - println("CALLING CI PREV S=$ved.prev_key_str") + println('CALLING CI PREV S=${ved.prev_key_str}') view.ci(key) return } @@ -982,8 +991,9 @@ fn (mut ved Ved) key_normal(key gg.KeyCode, mod gg.Modifier) { // < ved.view.shift_left() } else if super { - ved.cfg.reload_config() - ved.update_view() + // + // ved.cfg.reload_config() + // ved.update_view() } } .slash { @@ -1015,7 +1025,7 @@ fn (mut ved Ved) key_normal(key gg.KeyCode, mod gg.Modifier) { } .minus { if shift_and_super { - println('FONT DECREASE') + // println('FONT DECREASE') ved.increase_font(-1) } else if super { ved.get_git_diff_full() @@ -1026,7 +1036,7 @@ fn (mut ved Ved) key_normal(key gg.KeyCode, mod gg.Modifier) { ved.prev_key = .equal } else if shift_and_super { ved.increase_font(1) - println('FONT INCREASE') + // println('FONT INCREASE') } } .f12 { @@ -1623,15 +1633,15 @@ fn (mut ved Ved) dot() { fn (mut ved Ved) next_split() { ved.cur_split++ - if ved.cur_split % ved.splits_per_workspace == 0 { - ved.cur_split -= ved.splits_per_workspace + if ved.cur_split % ved.nr_splits == 0 { + ved.cur_split -= ved.nr_splits } ved.update_view() } fn (mut ved Ved) prev_split() { - if ved.cur_split % ved.splits_per_workspace == 0 { - ved.cur_split += ved.splits_per_workspace - 1 + if ved.cur_split % ved.nr_splits == 0 { + ved.cur_split += ved.nr_splits - 1 } else { ved.cur_split-- } @@ -1655,7 +1665,7 @@ fn (mut ved Ved) open_workspace(idx int) { ved.workspace = ved.workspaces[idx] // Update cur split index. If we are in space 0 split 1 and go to // space 1, split is updated to 4 (1 + 3 * (1-0)) - ved.cur_split += diff * ved.splits_per_workspace + ved.cur_split += diff * ved.nr_splits for i, view in ved.views { // Maybe the file is not loaded correctly (can happen on ved's launch) @@ -1871,7 +1881,7 @@ fn (mut ved Ved) open_blog() { } fn (ved &Ved) get_last_view() &View { - pos := (ved.workspace_idx + 1) * ved.splits_per_workspace - 1 + pos := (ved.workspace_idx + 1) * ved.nr_splits - 1 eprintln('> ${@METHOD} pos: ${pos}') unsafe { return &ved.views[pos] @@ -1926,8 +1936,8 @@ fn (mut ved Ved) go_to_error(line string) { col := vals[2].int() println('path=${path} filename=${filename} linenr=${line_nr} col=${col}') // Search for the file with the eror in all views inside current workspace - start_i := ved.workspace_idx * ved.splits_per_workspace - end_i := (ved.workspace_idx + 1) * ved.splits_per_workspace + start_i := ved.workspace_idx * ved.nr_splits + end_i := (ved.workspace_idx + 1) * ved.nr_splits for i := start_i; i < end_i && i < ved.views.len; i++ { mut view := unsafe { &ved.views[i] } if !view.path.contains(os.path_separator + filename) && view.path != filename { @@ -2081,12 +2091,21 @@ fn (mut ved Ved) git_pull() { const text_scale = 1.2 +const max_text_size = 24 +const min_text_size = 18 + fn (mut ved Ved) increase_font(delta int) { - // ved.cfg.text_size = int(f64(ved.cfg.text_size) * text_scale) - // ved.cfg.char_width = int(f64(ved.cfg.char_width) * text_scale) - // ved.cfg.line_height = int(f64(ved.cfg.line_height) * text_scale) + // println('INCREASE_FONT(${delta})') + // println('text_size=${ved.cfg.text_size}') + // println('char_width=${ved.cfg.char_width}') + // println('line_height=${ved.cfg.line_height}') ved.cfg.text_size += delta * 2 - if ved.cfg.text_size > 24 { + if ved.cfg.text_size > max_text_size { + ved.cfg.text_size = max_text_size + return + } + if ved.cfg.text_size < min_text_size { + ved.cfg.text_size = min_text_size return } ved.cfg.char_width += delta @@ -2113,11 +2132,21 @@ fn (mut ved Ved) increase_font(delta int) { ...ved.cfg.string_cfg size: ved.cfg.text_size } + // println('NEW text_size=${ved.cfg.text_size}') + // println('NEW char_width=${ved.cfg.char_width}') + // println('NEW line_height=${ved.cfg.line_height}\n') + ved.calc_nr_splits_from_text_size() + ved.save_config2() + // println('NEW CONFIG') + // println(ved.cfg) +} + +fn (mut ved Ved) calc_nr_splits_from_text_size() { if ved.cfg.text_size > 20 && ved.nr_splits > 2 { ved.nr_splits = 2 + } else if ved.cfg.text_size <= 20 { + ved.nr_splits = ved.get_nr_splits_from_screen_size(ved.win_width, ved.win_height) } - // println('NEW CONFIG') - // println(ved.cfg) } fn filter_ascii_colors(s string) string { @@ -2142,8 +2171,8 @@ fn (ved &Ved) get_nr_splits_from_screen_size(width int, height int) int { } fn (ved &Ved) get_splits_from_to() (int, int) { - from := ved.workspace_idx * ved.splits_per_workspace - to := from + ved.splits_per_workspace + from := ved.workspace_idx * ved.nr_splits + to := from + ved.nr_splits return from, to } diff --git a/view.v b/view.v index ff7257d..b44ac2a 100644 --- a/view.v +++ b/view.v @@ -83,7 +83,12 @@ fn (mut view View) open_file(path string, line_nr int) { view.short_path = view.short_path[1..] } } else { - view.short_path = path + // Optimize space, replace /Users/username with ~ + if path.starts_with(home_dir) { + view.short_path = path.replace(home_dir, '~') + } else { + view.short_path = path + } } mut ved := view.ved ved.set_current_syntax_idx(os.file_ext(path)) @@ -791,11 +796,10 @@ fn (mut view View) ci(key gg.KeyCode) { view.x = start + 1 view.ved.set_insert() } - ._9 { - } + ._9 {} else {} } - //match + // match // view.dw() }