diff --git a/cmd/tools/vcheck-md.v b/cmd/tools/vcheck-md.v index 83ff77e0fe..f7f63f9c2e 100644 --- a/cmd/tools/vcheck-md.v +++ b/cmd/tools/vcheck-md.v @@ -9,6 +9,7 @@ import rand import term import vhelp import v.pref +import regex const ( too_long_line_length = 100 @@ -162,6 +163,7 @@ fn (mut f MDFile) progress(message string) { fn (mut f MDFile) check() CheckResult { mut res := CheckResult{} + mut anchor_data := AnchorData{} for j, line in f.lines { // f.progress('line: $j') if line.len > too_long_line_length { @@ -187,8 +189,14 @@ fn (mut f MDFile) check() CheckResult { res.errors++ } } + if f.state == .markdown { + anchor_data.add_links(j, line) + anchor_data.add_link_targets(j, line) + } + f.parse_line(j, line) } + anchor_data.check_link_target_match(f.path, mut res) res += f.check_examples() return res } @@ -234,6 +242,121 @@ fn (mut f MDFile) parse_line(lnumber int, line string) { } } +struct Headline { + line int + lable string + level int +} + +struct Anchor { + line int +} + +type AnchorTarget = Anchor | Headline + +struct AnchorLink { + line int + lable string +} + +struct AnchorData { +mut: + links map[string][]AnchorLink + anchors map[string][]AnchorTarget +} + +fn (mut ad AnchorData) add_links(line_number int, line string) { + query := r'\[(?P[^\]]+)\]\(\s*#(?P[a-z\-]+)\)' + mut re := regex.regex_opt(query) or { panic(err) } + res := re.find_all_str(line) + + for elem in res { + re.match_string(elem) + link := re.get_group_by_name(elem, 'link') + ad.links[link] << AnchorLink{ + line: line_number + lable: re.get_group_by_name(elem, 'lable') + } + } +} + +fn (mut ad AnchorData) add_link_targets(line_number int, line string) { + if line.trim_space().starts_with('#') { + if headline_start_pos := line.index(' ') { + headline := line.substr(headline_start_pos + 1, line.len) + link := create_ref_link(headline) + ad.anchors[link] << Headline{ + line: line_number + lable: headline + level: headline_start_pos + } + } + } else { + query := r'[a-z\-]+)["\']\s*/>' + mut re := regex.regex_opt(query) or { panic(err) } + res := re.find_all_str(line) + + for elem in res { + re.match_string(elem) + link := re.get_group_by_name(elem, 'link') + ad.anchors[link] << Anchor{ + line: line_number + } + } + } +} + +fn (mut ad AnchorData) check_link_target_match(fpath string, mut res CheckResult) { + mut checked_headlines := []string{} + mut found_error_warning := false + for link, linkdata in ad.links { + if link in ad.anchors { + checked_headlines << link + if ad.anchors[link].len > 1 { + found_error_warning = true + res.errors++ + for anchordata in ad.anchors[link] { + eprintln(eline(fpath, anchordata.line, 0, 'multiple link targets of existing link (#$link)')) + } + } + } else { + found_error_warning = true + res.errors++ + for brokenlink in linkdata { + eprintln(eline(fpath, brokenlink.line, 0, 'no link target found for existing link [$brokenlink.lable](#$link)')) + } + } + } + for link, anchor_lists in ad.anchors { + if !(link in checked_headlines) { + if anchor_lists.len > 1 { + for anchor in anchor_lists { + line := match anchor { + Headline { + anchor.line + } + Anchor { + anchor.line + } + } + wprintln(wline(fpath, line, 0, 'multiple link target for non existing link (#$link)')) + found_error_warning = true + res.warnings++ + } + } + } + } + if found_error_warning { + eprintln('') // fix suppressed last error output + } +} + +fn create_ref_link(s string) string { + query_remove := r'[^a-z \-]' + mut re := regex.regex_opt(query_remove) or { panic(err) } + return re.replace_simple(s.to_lower(), '').replace(' ', '-') +} + fn (mut f MDFile) debug() { for e in f.examples { eprintln('f.path: $f.path | example: $e') diff --git a/doc/docs.md b/doc/docs.md index c948849c5f..7cbf8e185a 100644 --- a/doc/docs.md +++ b/doc/docs.md @@ -83,7 +83,7 @@ For more details and troubleshooting, please visit the [vab GitHub repository](h * [Structs](#structs) * [Embedded structs](#embedded-structs) * [Default field values](#default-field-values) - * [Short struct literal syntax](#short-struct-initialization-syntax) + * [Short struct literal syntax](#short-struct-literal-syntax) * [Access modifiers](#access-modifiers) * [Methods](#methods) * [Unions](#unions) @@ -2270,7 +2270,7 @@ You can also install modules already created by someone else with [VPM](https:// ```powershell v install [module] ``` -###### Example: +**Example:** ```powershell v install ui ``` @@ -2280,7 +2280,7 @@ Removing a module with v: ```powershell v remove [module] ``` -###### Example: +**Example:** ```powershell v remove ui ``` @@ -2290,7 +2290,7 @@ Updating an installed module from [VPM](https://vpm.vlang.io/): ```powershell v update [module] ``` -###### Example: +**Example:** ```powershell v update ui ``` @@ -2305,7 +2305,7 @@ To see all the modules you have installed, you can use: ```powershell v list ``` -###### Example +**Example:** ```powershell > v list Installed modules: @@ -2318,7 +2318,7 @@ outdated Show installed modules that need updates. ```powershell v outdated ``` -###### Example +**Example:** ```powershell > v outdated Modules are up to date. @@ -4024,7 +4024,7 @@ created by the JS Backend (flag: `-b js`). `$` is used as a prefix for compile-time operations. -#### $if +#### `$if` condition ```v // Support for multiple conditions in one branch $if ios || android { @@ -4076,7 +4076,7 @@ Full list of builtin options: | `gnu`, `hpux`, `haiku`, `qnx` | `cplusplus` | `big_endian` | | `solaris` | | | | -#### $embed_file +#### `$embed_file` ```v ignore import os @@ -4099,7 +4099,7 @@ executable, increasing your binary size, but making it more self contained and thus easier to distribute. In this case, `f.data()` will cause *no IO*, and it will always return the same data. -#### $tmpl for embedding and parsing V template files +#### `$tmpl` for embedding and parsing V template files V has a simple template language for text and html templates, and they can easily be embedded via `$tmpl('path/to/template.txt')`: @@ -4149,7 +4149,7 @@ numbers: [1, 2, 3] -#### $env +#### `$env` ```v module main diff --git a/doc/upcoming.md b/doc/upcoming.md index bab10ce4b3..45a1d98e27 100644 --- a/doc/upcoming.md +++ b/doc/upcoming.md @@ -74,37 +74,37 @@ different capabilities: | structured data types | + | + | + | | ### Strengths -#### default +**default** - very fast - unlimited access from different coroutines - easy to handle -#### `mut` +**`mut`** - very fast - easy to handle -#### `shared` +**`shared`** - concurrent access from different coroutines - data type may be complex structure - sophisticated access possible (several statements within one `lock` block) -#### `atomic` +**`atomic`** - concurrent access from different coroutines - reasonably fast ### Weaknesses -#### default +**default** - read only -#### `mut` +**`mut`** - access only from one coroutine at a time -#### `shared` +**`shared`** - lock/unlock are slow - moderately difficult to handle (needs `lock` block) -#### `atomic` +**`atomic`** - limited to single (max. 64 bit) integers (and pointers) - only a small set of predefined operations possible - very difficult to handle correctly @@ -191,3 +191,5 @@ are sometimes surprising. Each statement should be seen as a single transaction that is unrelated to the previous or following statement. Therefore - but also for performance reasons - it's often better to group consecutive coherent statements in an explicit `lock` block. + +### Channels diff --git a/doc/vscode.md b/doc/vscode.md index 3d037955f4..e1e1b35a3f 100644 --- a/doc/vscode.md +++ b/doc/vscode.md @@ -23,7 +23,7 @@ provides V language support for Visual Studio Code. [install V compiler](https://github.com/vlang/v/blob/master/doc/docs.md#install-from-source) on your operating system. -### Setup +### Setup Extention Install [V VS Code Extention](https://marketplace.visualstudio.com/items?itemName=vlanguage.vscode-vlang). @@ -45,7 +45,7 @@ for Visual Studio Code provides visual conditional debugging. [DWARF](https://en.wikipedia.org/wiki/DWARF) information to show and edit the variable. -### Setup +### Setup Debugging 1. Install the [C/C++ Extention](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools) 2. Open `RUN AND DEBUG` panel (Debug Icon in left panel). diff --git a/vlib/v/TEMPLATES.md b/vlib/v/TEMPLATES.md index a0d967af2e..25806d22c9 100644 --- a/vlib/v/TEMPLATES.md +++ b/vlib/v/TEMPLATES.md @@ -1,9 +1,11 @@ -This package is to generate data-driven HTML output. +V allows for easily using text templates, expanded at compile time to +V functions, that efficiently produce text output. This is especially +usefull for templated HTML views, but the mechanism is general enough +to be used for other kinds of text output also. -# Directives -Each directive begins with an `@` sign. -Some directives begin contains a `{}` block, others only have `''` (string) parameters. -More on the directives itself. +# Template directives +Each template directive begins with an `@` sign. +Some directives contain a `{}` block, others only have `''` (string) parameters. Newlines on the beginning and end are ignored in `{}` blocks, otherwise this (see [if](#if) for this syntax): @@ -12,17 +14,17 @@ otherwise this (see [if](#if) for this syntax): This is shown if bool_val is true } ``` -would result in: +... would output: ```html This is shown if bool_val is true ``` -which could result in unreadable output. +... which is less readable. ## if -The if directive consists of three parts, the `@if` tag, the condition (same syntax like in V) -and the `{}` block where you can write html which will be rendered if the condition is true: +The if directive, consists of three parts, the `@if` tag, the condition (same syntax like in V) +and the `{}` block, where you can write html, which will be rendered if the condition is true: ``` @if {} ``` @@ -42,19 +44,20 @@ The first example would result in: ```html This is shown if bool_val is true ``` -while the one-liner results in: +... while the one-liner results in: ```html This is shown if bool_val is true ``` ## for -The for directive consists of three parts, the `@for` tag, the condition (same syntax like in V) -and the `{}` block where you can write html which will be rendered for each loop: +The for directive consists of three parts, the `@for` tag, +the condition (same syntax like in V) and the `{}` block, +where you can write text, rendered for each iteration of the loop: ``` @for {} ``` -### Example +### Example for @for ```html @for i, val in my_vals { $i - $val @@ -72,7 +75,7 @@ The first example would result in: 2 - "Third" ... ``` -while the one-liner results in: +... while the one-liner results in: ```html 0 - "First" 1 - "Second" @@ -92,8 +95,7 @@ The include directive is for including other html files (which will be processed and consists of two parts, the `@include` tag and a following `''` string. The path parameter is relative to the `/templates` directory in the corresponding project. -### Example -Files +### Example for the folder structure of a project using templates: ``` Project root /templates @@ -117,11 +119,11 @@ where you can insert your src @js '' ``` -### Example +### Example for the @js directive: ```html @js 'myscripts.js' ``` # Variables -All variables which are declared before can be used through the `@{my_var}` syntax. +All variables, which are declared before the $tmpl can be used through the `@{my_var}` syntax. It's also possible to use properties of structs here like `@{my_struct.prop}`.