From: Jean Privat Date: Mon, 13 Aug 2018 19:25:30 +0000 (-0400) Subject: Merge: src/model/model_index: model index uses BKTree X-Git-Url: http://nitlanguage.org?hp=63ca7dcff113c0acd9acc030a296516cd39fbdb6 Merge: src/model/model_index: model index uses BKTree This PR makes ModelIndex use a BKTree (#2718) to speed up Nitweb name similarity search queries on large code corpora. Levenstein names comparison with 300k+ entities took a bit long (up to 10s for Nitweb with `contrib` and `src` for some queries). The use of BKTree speeds things up and brings those queries under 0.1s. Pull-Request: #2724 Reviewed-by: Jean Privat --- diff --git a/.gitignore b/.gitignore index c4cb96e..1463ddf 100644 --- a/.gitignore +++ b/.gitignore @@ -31,10 +31,12 @@ src/*.dat src/*.gnu src/*.bin src/nitc_0 +src/nitc_0.exe c_src/*.o c_src/*.cksum c_src/nitc +c_src/nitc.exe csrc2/ diff --git a/Makefile b/Makefile index 5029f2a..3557372 100644 --- a/Makefile +++ b/Makefile @@ -60,10 +60,6 @@ doc/stdlib/index.html: bin/nitdoc bin/nitls --custom-brand "Nitlanguage.org" \ --custom-overview-text "

Documentation for the standard library of Nit
Version $$(git describe)
Date: $$(git show --format="%cd" | head -1)

" \ --custom-footer-text "Nit standard library. Version $$(git describe)." \ - --github-upstream "nitlang:nit:master" \ - --github-base-sha1 "$$(git rev-parse HEAD)" \ - --github-gitdir "." \ - --source "https://github.com/nitlang/nit/blob/$$(git rev-parse HEAD)/%f#L%l-%L" \ --piwik-tracker "pratchett.info.uqam.ca/piwik/" \ --piwik-site-id "2" \ @@ -74,10 +70,6 @@ doc/nitc/index.html: bin/nitdoc bin/nitls --custom-brand "Nitlanguage.org" \ --custom-overview-text "

Documentation for the Nit tools
Version $$(git describe)
Date: $$(git show --format="%cd" | head -1)

" \ --custom-footer-text "Nit tools. Version $$(git describe)." \ - --github-upstream "nitlang:nit:master" \ - --github-base-sha1 "$$(git rev-parse HEAD)" \ - --github-gitdir "." \ - --source "https://github.com/nitlang/nit/blob/$$(git rev-parse HEAD)/%f#L%l-%L" \ --piwik-tracker "pratchett.info.uqam.ca/piwik/" \ --piwik-site-id "3" diff --git a/benchmarks/markdown/bench_markdown.sh b/benchmarks/markdown/bench_markdown.sh index d6826e1..338ba14 100755 --- a/benchmarks/markdown/bench_markdown.sh +++ b/benchmarks/markdown/bench_markdown.sh @@ -97,6 +97,30 @@ function bench_nitmd-o() } bench_nitmd-o +function bench_nitmd2() +{ + name="$FUNCNAME" + skip_test "$name" && return + prepare_res $outdir/nitmd2.dat "nitmd2" "nitmd2" + for file in $bncdir/*.md; do + bench=`basename $file .md` + bench_command "$bench" "" "$engdir/nitmd2/nitmd2" "$file" "$s" + done +} +bench_nitmd2 + +function bench_nitmd2-o() +{ + name="$FUNCNAME" + skip_test "$name" && return + prepare_res $outdir/nitmd2-o.dat "nitmd2-o" "nitmd2-o" + for file in $bncdir/*.md; do + bench=`basename $file .md` + bench_command "$bench" "" "$engdir/nitmd2/nitmd2-o" "$file" "$s" + done +} +bench_nitmd2-o + function bench_txtmark() { name="$FUNCNAME" diff --git a/benchmarks/markdown/engines/Makefile b/benchmarks/markdown/engines/Makefile index 1eeda88..711d69f 100644 --- a/benchmarks/markdown/engines/Makefile +++ b/benchmarks/markdown/engines/Makefile @@ -14,11 +14,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -all: nitmd/nitmd txtmark/Txtmark.class markdown4j/Markdown4j.class +all: nitmd/nitmd nitmd2/nitmd2 txtmark/Txtmark.class markdown4j/Markdown4j.class nitmd/nitmd: make -C nitmd +nitmd2/nitmd2: + make -C nitmd2 + txtmark/Txtmark.class: make -C txtmark @@ -30,6 +33,7 @@ pandoc/pandoc: clean: make -C nitmd clean + make -C nitmd2 clean make -C txtmark clean make -C markdown4j clean make -C pandoc clean diff --git a/benchmarks/markdown/engines/nitmd2/Makefile b/benchmarks/markdown/engines/nitmd2/Makefile new file mode 100644 index 0000000..526ca83 --- /dev/null +++ b/benchmarks/markdown/engines/nitmd2/Makefile @@ -0,0 +1,32 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Copyright 2015 Alexandre Terrasa +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +NITC=../../../../bin/nitc + +all: nitmd2 nitmd2-o + +nitmd2: + $(NITC) nitmd2.nit + +nitmd2-o: + $(NITC) --semi-global nitmd2.nit -o $@ + +test: all + ./nitmd2 ../../benches/hello.md 5 + ./nitmd2-o ../../benches/hello.md 5 + +clean: + rm -rf nitmd2 nitmd2-o diff --git a/src/doc/doc_phases/doc_phases.nit b/benchmarks/markdown/engines/nitmd2/nitmd2.nit similarity index 66% rename from src/doc/doc_phases/doc_phases.nit rename to benchmarks/markdown/engines/nitmd2/nitmd2.nit index 24969e4..d705618 100644 --- a/src/doc/doc_phases/doc_phases.nit +++ b/benchmarks/markdown/engines/nitmd2/nitmd2.nit @@ -4,7 +4,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, @@ -12,11 +12,15 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Phases represent the *steps* of the NitDoc generation process. -# -# See `DocPhase`. -module doc_phases +import markdown2 + +var file = args.first +var n = args[1].to_i -import doc_html -import doc_indexing -import doc_test +var str = file.to_path.read_all +var parser = new MdParser +var renderer = new HtmlRenderer +for i in [1..n] do + var doc = parser.parse(str) + print renderer.render(doc) +end diff --git a/clib/gc_chooser.h b/clib/gc_chooser.h index 255e07a..882d310 100644 --- a/clib/gc_chooser.h +++ b/clib/gc_chooser.h @@ -22,5 +22,6 @@ void initialize_gc_option(void); /* Select the wanted GC using envvar `NIT_GC_OP void gc_register_finalizer(void*); /* Tag a pointer for finalization */ void gc_finalize(void*, void*); /* Finalize a pointer, implemented in the generated code. */ +void object_destroy_callback(void*, void*); /* call into an object finalizer to record some traces. */ #endif diff --git a/clib/traces.c b/clib/traces.c index 4b01642..9e3c3ad 100644 --- a/clib/traces.c +++ b/clib/traces.c @@ -1,4 +1,8 @@ #define TRACEPOINT_CREATE_PROBES #define TRACEPOINT_DEFINE -#include "traces.h" +#include "nit.common.h" + +void object_destroy_callback(void *obj, void *cd){ + tracepoint(Nit_Compiler, Object_Destroy, (char*)((val*)(obj))->type->name, (uintptr_t)obj); +} diff --git a/clib/traces.h b/clib/traces.h index 1b88f68..b34af65 100644 --- a/clib/traces.h +++ b/clib/traces.h @@ -8,18 +8,32 @@ #define _TRACES_H #include +#include TRACEPOINT_EVENT( - Nit_Compiler, - Object_Instance, - TP_ARGS( - char*, object_class_arg, - int, object_id_arg - ), - TP_FIELDS( - ctf_string(object_class, object_class_arg) - ctf_integer(int, object_id, object_id_arg) - ) + Nit_Compiler, + Object_Instance, + TP_ARGS( + char*, object_class_arg, + int, object_id_arg + ), + TP_FIELDS( + ctf_string(object_class, object_class_arg) + ctf_integer(int, object_id, object_id_arg) + ) +) + +TRACEPOINT_EVENT( + Nit_Compiler, + Object_Destroy, + TP_ARGS( + char*, object_class_arg, + int, object_id_arg + ), + TP_FIELDS( + ctf_string(object_class, object_class_arg) + ctf_integer(int, object_id, object_id_arg) + ) ) #endif diff --git a/contrib/benitlux/src/server/benitlux_controller.nit b/contrib/benitlux/src/server/benitlux_controller.nit index a2ab392..8f96182 100644 --- a/contrib/benitlux/src/server/benitlux_controller.nit +++ b/contrib/benitlux/src/server/benitlux_controller.nit @@ -77,7 +77,7 @@ class BenitluxSubscriptionAction end var response = new HttpResponse(200) - response.body = template.write_to_string + response.body = template return response end end diff --git a/contrib/brainfuck/brainfuck.nit b/contrib/brainfuck/brainfuck.nit index 4216952..d207496 100644 --- a/contrib/brainfuck/brainfuck.nit +++ b/contrib/brainfuck/brainfuck.nit @@ -18,7 +18,7 @@ module brainfuck # Interpreter for Brainfuck source code. class BFInterpreter # Data cells - var dr = new Array[Byte] + var dr = new Array[Int] # Data pointer var dp = 0 # Instruction pointer @@ -29,7 +29,7 @@ class BFInterpreter # Create an interpreter for `program`. init do - dr.add 0u8 + dr.add 0 end # Create an interpreter for the file located at `path`. @@ -51,35 +51,35 @@ class BFInterpreter # Evaluates the current instruction fun eval do var instr = program[ip] - if instr == '.'.ascii then printn dr[dp].ascii - if instr == '['.ascii then - if dr[dp] == 0u8 then + if instr == u'.' then printn dr[dp].code_point + if instr == u'[' then + if dr[dp] == 0 then ip = find_matching_rbra return end end - if instr == ']'.ascii then - if dr[dp] != 0u8 then + if instr == u']' then + if dr[dp] != 0 then ip = find_matching_lbra return end end - if instr == '>'.ascii then + if instr == u'>' then dp += 1 - if dp >= dr.length then dr.add(0u8) + if dp >= dr.length then dr.add(0) end - if instr == '<'.ascii then + if instr == u'<' then dp -= 1 if dp < 0 then abort end - if instr == '+'.ascii then - dr[dp] = dr[dp] + 1u8 + if instr == u'+' then + dr[dp] = dr[dp] + 1 end - if instr == '-'.ascii then - dr[dp] = dr[dp] - 1u8 + if instr == u'-' then + dr[dp] = dr[dp] - 1 end - if instr == ','.ascii then - dr[dp] = getc.ascii + if instr == u',' then + dr[dp] = getc.code_point end end @@ -89,14 +89,14 @@ class BFInterpreter var lbracnt = 0 loop if pos > program.length then abort - if program[pos] == ']'.ascii then + if program[pos] == u']' then if lbracnt > 0 then lbracnt -= 1 else break end end - if program[pos] == '['.ascii then lbracnt += 1 + if program[pos] == u'[' then lbracnt += 1 pos += 1 end return pos @@ -108,14 +108,14 @@ class BFInterpreter var rbracnt = 0 loop if pos < 0 then abort - if program[pos] == '['.ascii then + if program[pos] == u'[' then if rbracnt > 0 then rbracnt -= 1 else break end end - if program[pos] == ']'.ascii then rbracnt += 1 + if program[pos] == u']' then rbracnt += 1 pos -= 1 end return pos diff --git a/contrib/nitiwiki/src/wiki_edit.nit b/contrib/nitiwiki/src/wiki_edit.nit index 3b1abb7..436760b 100644 --- a/contrib/nitiwiki/src/wiki_edit.nit +++ b/contrib/nitiwiki/src/wiki_edit.nit @@ -50,7 +50,7 @@ class WikiEditForm fun to_http_response: HttpResponse do var resp = new HttpResponse(200) - resp.body = tpl_page.write_to_string + resp.body = tpl_page return resp end end diff --git a/contrib/nitrpg/src/web.nit b/contrib/nitrpg/src/web.nit index f624f48..c563af7 100644 --- a/contrib/nitrpg/src/web.nit +++ b/contrib/nitrpg/src/web.nit @@ -50,7 +50,7 @@ class RpgAction var page = new NitRpgPage(root_url) var error = new ErrorPanel(msg) page.flow_panels.add error - rsp.body = page.write_to_string + rsp.body = page return rsp end @@ -95,7 +95,7 @@ class RpgHome page = new NitRpgPage(root_url) page.side_panels.add new GamesShortListPanel(root_url, games) page.flow_panels.add new MDPanel(readme) - response.body = page.write_to_string + response.body = page return response end @@ -126,7 +126,7 @@ class ListGames page.breadcrumbs = new Breadcrumbs page.breadcrumbs.add_link(root_url / "games", "games") page.flow_panels.add new GamesListPanel(root_url, games) - response.body = page.write_to_string + response.body = page return response end end @@ -196,7 +196,7 @@ class RepoHome page.flow_panels.add new PodiumPanel(game) page.flow_panels.add new EventListPanel(game, list_limit, list_from) page.flow_panels.add new AchievementsListPanel(game) - rsp.body = page.write_to_string + rsp.body = page return rsp end end @@ -210,7 +210,7 @@ class ListPlayers if is_response_error(rsp) then return rsp page.breadcrumbs.add_link(game.url / "players", "players") page.flow_panels.add new ListPlayersPanel(game) - rsp.body = page.write_to_string + rsp.body = page return rsp end end @@ -239,7 +239,7 @@ class PlayerHome page.flow_panels.add new PlayerWorkPanel(game, player) page.flow_panels.add new AchievementsListPanel(player) page.flow_panels.add new EventListPanel(player, list_limit, list_from) - rsp.body = page.write_to_string + rsp.body = page return rsp end end @@ -253,7 +253,7 @@ class ListAchievements if is_response_error(rsp) then return rsp page.breadcrumbs.add_link(game.url / "achievements", "achievements") page.flow_panels.add new AchievementsListPanel(game) - rsp.body = page.write_to_string + rsp.body = page return rsp end end @@ -278,7 +278,7 @@ class AchievementHome page.breadcrumbs.add_link(achievement.url, achievement.name) page.flow_panels.add new AchievementPanel(achievement) page.flow_panels.add new EventListPanel(achievement, list_limit, list_from) - rsp.body = page.write_to_string + rsp.body = page return rsp end end diff --git a/contrib/opportunity/src/opportunity_controller.nit b/contrib/opportunity/src/opportunity_controller.nit index 214c843..3266502 100644 --- a/contrib/opportunity/src/opportunity_controller.nit +++ b/contrib/opportunity/src/opportunity_controller.nit @@ -31,7 +31,7 @@ abstract class OpportunityAction # TODO: Add a specific body to the bad request page. fun bad_req: HttpResponse do var rsp = new HttpResponse(400) - rsp.body = (new OpportunityHomePage).write_to_string + rsp.body = new OpportunityHomePage return rsp end end @@ -73,7 +73,7 @@ class OpportunityWelcome meetpage.ans = ansset meetpage.meet = meet meetpage.error = "'Meetup name' is a mandatory fields." - rsp.body = meetpage.write_to_string + rsp.body = meetpage return rsp end @@ -85,7 +85,7 @@ class OpportunityWelcome var meetpage = new MeetupCreationPage meetpage.meet = meet meetpage.error = "You need to input at least one answer." - rsp.body = meetpage.write_to_string + rsp.body = meetpage return rsp end @@ -100,7 +100,7 @@ class OpportunityWelcome

Failed to create event

This is a server side error, it has been logged. You may still want to contact the maintainers of this website.

""" - rsp.body = meetpage.write_to_string + rsp.body = meetpage return rsp end @@ -111,22 +111,22 @@ class OpportunityWelcome end db.close var rsp = new HttpResponse(200) - rsp.body = (new MeetupConfirmation(meet)).write_to_string + rsp.body = new MeetupConfirmation(meet) return rsp end if rq.has("new_meetup") then var rsp = new HttpResponse(200) var page = new MeetupCreationPage - rsp.body = page.write_to_string + rsp.body = page return rsp end if get.has_key("meetup_id") then var rsp = new HttpResponse(200) - rsp.body = (new OpportunityMeetupPage.from_id(get["meetup_id"])).write_to_string + rsp.body = new OpportunityMeetupPage.from_id(get["meetup_id"]) return rsp end var rsp = new HttpResponse(200) - rsp.body = (new OpportunityHomePage).write_to_string + rsp.body = new OpportunityHomePage return rsp end diff --git a/contrib/pep8analysis/src/parser/xss/lexer.xss b/contrib/pep8analysis/src/parser/xss/lexer.xss index 6a4d1d0..802755f 100644 --- a/contrib/pep8analysis/src/parser/xss/lexer.xss +++ b/contrib/pep8analysis/src/parser/xss/lexer.xss @@ -107,7 +107,7 @@ $ end foreach if sp >= string_len then dfa_state = -1 else - var c = string[sp].ascii + var c = string[sp].code_point sp += 1 var cr = _cr diff --git a/examples/leapfrog/leapfrog_curses.nit b/examples/leapfrog/leapfrog_curses.nit index da05bf8..995adde 100644 --- a/examples/leapfrog/leapfrog_curses.nit +++ b/examples/leapfrog/leapfrog_curses.nit @@ -124,7 +124,7 @@ redef class PlayScene while sys.stdin.poll_in do if sys.stdin.eof then return var c = sys.stdin.read_char - if c == 'q'.ascii then + if c == u'q' then self.exists = false return end diff --git a/examples/rosettacode/vignere_cipher.nit b/examples/rosettacode/vignere_cipher.nit index 565c19e..7fea059 100644 --- a/examples/rosettacode/vignere_cipher.nit +++ b/examples/rosettacode/vignere_cipher.nit @@ -19,7 +19,7 @@ fun encrypt(src, key: String): String do continue end - out.add(((c.ascii + key[j].ascii - 2u8 * 'A'.ascii) % 26u8 + 'A'.ascii).ascii) + out.add(((c.code_point + key[j].code_point - 2 * u'A') % 26 + u'A').code_point) j = (j + 1) % key.length end @@ -39,7 +39,7 @@ fun decrypt(src, key: String): String do continue end - out.add(((c.ascii - key[j].ascii + 26u8) % 26u8 + 'A'.ascii).ascii) + out.add(((c.code_point - key[j].code_point + 26) % 26 + u'A').code_point) j = (j + 1) % key.length end diff --git a/lib/actors/examples/mandelbrot/mandelbrot.nit b/lib/actors/examples/mandelbrot/mandelbrot.nit index f756970..8fa7be3 100644 --- a/lib/actors/examples/mandelbrot/mandelbrot.nit +++ b/lib/actors/examples/mandelbrot/mandelbrot.nit @@ -54,8 +54,8 @@ class Worker return res ^-1 end - fun put_line(y: Int, line: Array[Byte]) do - for i in [0..line.length[ do line[i] = get_byte(i * 8, y).to_b + fun put_line(y: Int, line: Array[Int]) do + for i in [0..line.length[ do line[i] = get_byte(i * 8, y) end fun work do @@ -70,7 +70,7 @@ end redef class Sys var n = 0 var inv_n: Float is noautoinit - var data: Array[Array[Byte]] is noautoinit + var data: Array[Array[Int]] is noautoinit var crb: Array[Float] is noautoinit var cib: Array[Float] is noautoinit var atomic = new AtomicInt(0) @@ -89,8 +89,8 @@ for i in [0..n[ do sys.cib[i] = i.to_f * inv_n - 1.0 sys.crb[i] = i.to_f * inv_n - 1.5 end -sys.data = new Array[Array[Byte]].with_capacity(n) -for i in [0..n[ do sys.data[i] = new Array[Byte].filled_with(0.to_b, (n) / 8) +sys.data = new Array[Array[Int]].with_capacity(n) +for i in [0..n[ do sys.data[i] = new Array[Int].filled_with(0, (n) / 8) # Parallel Approach var actors = new Array[Worker] diff --git a/lib/base64/base64.nit b/lib/base64/base64.nit index 26e1207..622bb51 100644 --- a/lib/base64/base64.nit +++ b/lib/base64/base64.nit @@ -21,38 +21,38 @@ redef class Char # Is `self` a valid Base64 character ? fun is_base64_char: Bool do if code_point >= 127 then return false - return ascii.is_base64_char + return code_point.is_base64_char end end -redef class Byte +redef class Int # Is `self` a valid Base64 character ? fun is_base64_char: Bool do - if self == b'+' then return true - if self == b'/' then return true - if self > b'Z' then - if self < b'a' then return false - if self <= b'z' then return true + if self == u'+' then return true + if self == u'/' then return true + if self > u'Z' then + if self < u'a' then return false + if self <= u'z' then return true return false end - if self >= b'A' then return true - if self <= b'9' and self >= b'0' then return true + if self >= u'A' then return true + if self <= u'9' and self >= u'0' then return true return false end # Returns the `base64` equivalent of `self` # # REQUIRE `self`.`is_base64_char` - fun to_base64_char: Byte do - if self == b'+' then return 62u8 - if self == b'/' then return 63u8 - if self > b'Z' then - if self < b'a' then abort - if self <= b'z' then return self - 71u8 + fun to_base64_char: Int do + if self == u'+' then return 62 + if self == u'/' then return 63 + if self > u'Z' then + if self < u'a' then abort + if self <= u'z' then return self - 71 abort end - if self >= b'A' then return self - 0x41u8 - if self <= b'9' and self >= b'0' then return self + 4u8 + if self >= u'A' then return self - 0x41 + if self <= u'9' and self >= u'0' then return self + 4 abort end end @@ -79,26 +79,26 @@ redef class CString var in_off = 0 for s in [0 .. steps[ do - var ind = ((self[in_off] & 0b1111_1100u8) >> 2).to_i + var ind = (self[in_off] & 0b1111_1100) >> 2 result.add base64_bytes[ind] - ind = ((self[in_off] & 0b0000_0011u8) << 4).to_i | ((self[in_off + 1] & 0b1111_0000u8) >> 4).to_i + ind = ((self[in_off] & 0b0000_0011) << 4) | ((self[in_off + 1] & 0b1111_0000) >> 4) result.add base64_bytes[ind] - ind = ((self[in_off + 1] & 0b0000_1111u8) << 2).to_i | ((self[in_off + 2] & 0b1100_0000u8) >> 6).to_i + ind = ((self[in_off + 1] & 0b0000_1111) << 2) | ((self[in_off + 2] & 0b1100_0000) >> 6) result.add base64_bytes[ind] - ind = (self[in_off + 2] & 0b0011_1111u8).to_i + ind = (self[in_off + 2] & 0b0011_1111) result.add base64_bytes[ind] in_off += 3 end if bytes_in_last_step == 1 then - result.add base64_bytes[((self[in_off] & 0b1111_1100u8) >> 2).to_i] - result.add base64_bytes[((self[in_off] & 0b0000_0011u8) << 4).to_i] + result.add base64_bytes[(self[in_off] & 0b1111_1100) >> 2] + result.add base64_bytes[(self[in_off] & 0b0000_0011) << 4] else if bytes_in_last_step == 2 then - result.add base64_bytes[((self[in_off] & 0b1111_1100u8) >> 2).to_i] - result.add base64_bytes[(((self[in_off] & 0b0000_0011u8) << 4) | ((self[in_off + 1] & 0b1111_0000u8) >> 4)).to_i] - result.add base64_bytes[((self[in_off + 1] & 0b0000_1111u8) << 2).to_i] + result.add base64_bytes[(self[in_off] & 0b1111_1100) >> 2] + result.add base64_bytes[((self[in_off] & 0b0000_0011) << 4) | ((self[in_off + 1] & 0b1111_0000) >> 4)] + result.add base64_bytes[(self[in_off + 1] & 0b0000_1111) << 2] end var rempad = if bytes_in_last_step > 0 then 3 - bytes_in_last_step else 0 - for i in [0 .. rempad[ do result.add b'=' + for i in [0 .. rempad[ do result.add u'=' return result end @@ -116,7 +116,7 @@ redef class CString if length == 0 then return new Bytes.empty # Avoids constant unboxing - var pad = b'=' + var pad = '=' var result = new Bytes.with_capacity((length / 4 + 1) * 3) @@ -130,15 +130,15 @@ redef class CString break end # Ignore whitespaces - if b <= 0x20u8 then continue + if b <= 0x20 then continue if not b.is_base64_char then continue curr <<= 6 curr += b.to_base64_char.to_i cnt += 1 if cnt == 4 then - result.add(((curr & 0xFF0000) >> 16).to_b) - result.add(((curr & 0xFF00) >> 8).to_b) - result.add((curr & 0xFF).to_b) + result.add ((curr & 0xFF0000) >> 16) + result.add ((curr & 0xFF00) >> 8) + result.add (curr & 0xFF) curr = 0 cnt = 0 end @@ -147,16 +147,16 @@ redef class CString var pads = 0 for i in [endpos .. length[ do var b = self[i] - if b <= 0x20u8 then continue + if b <= 0x20 then continue pads += 1 end if cnt == 2 then curr >>= 4 - result.add(curr.to_b) + result.add(curr) else if cnt == 3 then curr >>= 2 - result.add(((curr & 0xFF00) >> 8).to_b) - result.add((curr & 0xFF).to_b) + result.add ((curr & 0xFF00) >> 8) + result.add (curr & 0xFF) end end return result @@ -177,19 +177,19 @@ redef class CString var rlen = 0 var opos = length for i in [0 .. length[ do - if self[i] == b'=' then + if self[i] == u'=' then opos = i break end if self[i].is_whitespace then continue - if not self[i].is_base64_char then return new Error("Invalid Base64 character at position {i}: {self[i].ascii}") + if not self[i].is_base64_char then return new Error("Invalid Base64 character at position {i}: {self[i].code_point}") rlen += 1 if rlen > 4 then rlen -= 4 end var pad = 0 for i in [opos .. length[ do if self[i].is_whitespace then continue - if self[i] != b'=' then return new Error("Invalid padding character {self[i].ascii} at position {i}") + if self[i] != u'=' then return new Error("Invalid padding character {self[i].code_point} at position {i}") pad += 1 end if rlen + pad != 4 then return new Error("Invalid padding length") diff --git a/lib/binary/binary.nit b/lib/binary/binary.nit index b8f8b5c..8b39d31 100644 --- a/lib/binary/binary.nit +++ b/lib/binary/binary.nit @@ -18,7 +18,7 @@ # var w = new FileWriter.open("/tmp/data.bin") # w.write "hello" # w.write_int64 123456789 -# w.write_byte 3u8 +# w.write_byte 3 # w.write_float 1.25 # w.write_double 1.234567 # w.write_bits(true, false, true) @@ -70,7 +70,7 @@ redef abstract class Writer super BinaryStream # Write a boolean `value` on a byte, using 0 for `false` and 1 for `true` - fun write_bool(value: Bool) do write_byte if value then 1u8 else 0u8 + fun write_bool(value: Bool) do write_byte if value then 1 else 0 # Write up to 8 `Bool` in a byte # @@ -81,9 +81,9 @@ redef abstract class Writer do assert bits.length <= 8 - var int = 0u8 + var int = 0 for b in bits.length.times do - if bits[b] then int |= 1u8 << (7 - b) + if bits[b] then int |= 1 << (7 - b) end write_byte int @@ -97,7 +97,7 @@ redef abstract class Writer fun write_string(text: Text) do write text - write_byte 0x00u8 + write_byte 0x00 end # Write the length as a 64 bits integer, then the content of `text` @@ -184,7 +184,7 @@ redef abstract class Reader if byte <= 0 then return buf.to_s end - buf.add byte.to_b + buf.add byte end end @@ -341,7 +341,7 @@ end redef class Int # Utility for `BinaryWriter` - private fun int64_byte_at(index: Int, big_endian: Bool): Byte `{ + private fun int64_byte_at(index: Int, big_endian: Bool): Int `{ union { unsigned char bytes[8]; int64_t val; @@ -360,7 +360,7 @@ end redef class Float # Utility for `BinaryWriter` - private fun float_byte_at(index: Int, big_endian: Bool): Byte `{ + private fun float_byte_at(index: Int, big_endian: Bool): Int `{ union { unsigned char bytes[4]; float val; @@ -377,7 +377,7 @@ redef class Float `} # Utility for `BinaryWriter` - private fun double_byte_at(index: Int, big_endian: Bool): Byte `{ + private fun double_byte_at(index: Int, big_endian: Bool): Int `{ union { unsigned char bytes[8]; double val; diff --git a/lib/core/bytes.nit b/lib/core/bytes.nit index 84276ac..f386c47 100644 --- a/lib/core/bytes.nit +++ b/lib/core/bytes.nit @@ -22,83 +22,83 @@ intrude import text::flat # Any kind of entity which can be searched for in a Sequence of Byte interface BytePattern # Return the first occurence of `self` in `b`, or -1 if not found - fun first_index_in(b: SequenceRead[Byte]): Int do return first_index_in_from(b, 0) + fun first_index_in(b: SequenceRead[Int]): Int do return first_index_in_from(b, 0) # Return the first occurence of `self` in `b` starting at `from`, or -1 if not found - fun first_index_in_from(b: SequenceRead[Byte], from: Int): Int is abstract + fun first_index_in_from(b: SequenceRead[Int], from: Int): Int is abstract # Return the last occurence of `self` in `b`, or -1 if not found - fun last_index_in(b: SequenceRead[Byte]): Int do return last_index_in_from(b, b.length - 1) + fun last_index_in(b: SequenceRead[Int]): Int do return last_index_in_from(b, b.length - 1) # Return the last occurence of `self` in `b`, or -1 if not found - fun last_index_in_from(b: SequenceRead[Byte], from: Int): Int is abstract + fun last_index_in_from(b: SequenceRead[Int], from: Int): Int is abstract # Returns the indexes of all the occurences of `self` in `b` - fun search_all_in(b: SequenceRead[Byte]): SequenceRead[Int] is abstract + fun search_all_in(b: SequenceRead[Int]): SequenceRead[Int] is abstract # Length of the pattern fun pattern_length: Int is abstract # Appends `self` to `b` - fun append_to(b: Sequence[Byte]) is abstract + fun append_to(b: Sequence[Int]) is abstract # Is `self` a prefix for `b` ? - fun is_prefix(b: SequenceRead[Byte]): Bool is abstract + fun is_prefix(b: SequenceRead[Int]): Bool is abstract # Is `self` a suffix for `b` ? - fun is_suffix(b: SequenceRead[Byte]): Bool is abstract + fun is_suffix(b: SequenceRead[Int]): Bool is abstract end -redef class Byte +redef class Int super BytePattern # Write self as a string into `ns` at position `pos` private fun add_digest_at(ns: CString, pos: Int) do - var tmp = (0xF0u8 & self) >> 4 - ns[pos] = if tmp >= 0x0Au8 then tmp + 0x37u8 else tmp + 0x30u8 - tmp = 0x0Fu8 & self - ns[pos + 1] = if tmp >= 0x0Au8 then tmp + 0x37u8 else tmp + 0x30u8 + var tmp = (0xF0 & self) >> 4 + ns[pos] = if tmp >= 0x0A then tmp + 0x37 else tmp + 0x30 + tmp = 0x0F & self + ns[pos + 1] = if tmp >= 0x0A then tmp + 0x37 else tmp + 0x30 end # Is `self` a valid hexadecimal digit (in ASCII) # # ~~~nit # intrude import core::bytes - # assert not '/'.ascii.is_valid_hexdigit - # assert '0'.ascii.is_valid_hexdigit - # assert '9'.ascii.is_valid_hexdigit - # assert not ':'.ascii.is_valid_hexdigit - # assert not '@'.ascii.is_valid_hexdigit - # assert 'A'.ascii.is_valid_hexdigit - # assert 'F'.ascii.is_valid_hexdigit - # assert not 'G'.ascii.is_valid_hexdigit - # assert not '`'.ascii.is_valid_hexdigit - # assert 'a'.ascii.is_valid_hexdigit - # assert 'f'.ascii.is_valid_hexdigit - # assert not 'g'.ascii.is_valid_hexdigit + # assert not u'/'.is_valid_hexdigit + # assert u'0'.is_valid_hexdigit + # assert u'9'.is_valid_hexdigit + # assert not u':'.is_valid_hexdigit + # assert not u'@'.is_valid_hexdigit + # assert u'A'.is_valid_hexdigit + # assert u'F'.is_valid_hexdigit + # assert not u'G'.is_valid_hexdigit + # assert not u'`'.is_valid_hexdigit + # assert u'a'.is_valid_hexdigit + # assert u'f'.is_valid_hexdigit + # assert not u'g'.is_valid_hexdigit # ~~~ private fun is_valid_hexdigit: Bool do - return (self >= 0x30u8 and self <= 0x39u8) or - (self >= 0x41u8 and self <= 0x46u8) or - (self >= 0x61u8 and self <= 0x66u8) + return (self >= 0x30 and self <= 0x39) or + (self >= 0x41 and self <= 0x46) or + (self >= 0x61 and self <= 0x66) end # `self` as a hexdigit to its byte value # # ~~~nit # intrude import core::bytes - # assert 0x39u8.hexdigit_to_byteval == 0x09u8 - # assert 0x43u8.hexdigit_to_byteval == 0x0Cu8 + # assert 0x39.hexdigit_to_byteval == 0x09 + # assert 0x43.hexdigit_to_byteval == 0x0C # ~~~ # # REQUIRE: `self.is_valid_hexdigit` - private fun hexdigit_to_byteval: Byte do - if self >= 0x30u8 and self <= 0x39u8 then - return self - 0x30u8 - else if self >= 0x41u8 and self <= 0x46u8 then - return self - 0x37u8 - else if self >= 0x61u8 and self <= 0x66u8 then - return self - 0x57u8 + private fun hexdigit_to_byteval: Int do + if self >= 0x30 and self <= 0x39 then + return self - 0x30 + else if self >= 0x41 and self <= 0x46 then + return self - 0x37 + else if self >= 0x61 and self <= 0x66 then + return self - 0x57 end # Happens only if the requirement is not met. # i.e. this abort is here to please the compiler @@ -130,20 +130,113 @@ redef class Byte redef fun append_to(b) do b.push self - # assert 'b'.ascii.is_suffix("baqsdb".to_bytes) - # assert not 'b'.ascii.is_suffix("baqsd".to_bytes) + # assert u'b'.is_suffix("baqsdb".to_bytes) + # assert not u'b'.is_suffix("baqsd".to_bytes) redef fun is_suffix(b) do return b.length != 0 and b.last == self - # assert 'b'.ascii.is_prefix("baqsdb".to_bytes) - # assert not 'b'.ascii.is_prefix("aqsdb".to_bytes) + # assert u'b'.is_prefix("baqsdb".to_bytes) + # assert not u'b'.is_prefix("aqsdb".to_bytes) redef fun is_prefix(b) do return b.length != 0 and b.first == self + + # A signed big-endian representation of `self` + # + # ~~~ + # assert 1.to_bytes.hexdigest == "01" + # assert 255.to_bytes.hexdigest == "FF" + # assert 256.to_bytes.hexdigest == "0100" + # assert 65535.to_bytes.hexdigest == "FFFF" + # assert 65536.to_bytes.hexdigest == "010000" + # ~~~ + # + # Negative values are converted to their two's complement. + # Be careful as the result can be ambiguous. + # + # ~~~ + # assert (-1).to_bytes.hexdigest == "FF" + # assert (-32).to_bytes.hexdigest == "E0" + # assert (-512).to_bytes.hexdigest == "FE00" + # assert (-65794).to_bytes.hexdigest == "FEFEFE" + # ~~~ + # + # Optionally, set `n_bytes` to the desired number of bytes in the output. + # This setting can disambiguate the result between positive and negative + # integers. Be careful with this parameter as the result may overflow. + # + # ~~~ + # assert 1.to_bytes(2).hexdigest == "0001" + # assert 65535.to_bytes(2).hexdigest == "FFFF" + # assert (-1).to_bytes(2).hexdigest == "FFFF" + # assert (-512).to_bytes(4).hexdigest == "FFFFFE00" + # assert 0x123456.to_bytes(2).hexdigest == "3456" + # ~~~ + # + # For 0, a Bytes object with single nul byte is returned (instead of an empty Bytes object). + # + # ~~~ + # assert 0.to_bytes.hexdigest == "00" + # ~~~ + # + # For positive integers, `Bytes::to_i` can reverse the operation. + # + # ~~~ + # assert 1234.to_bytes.to_i == 1234 + # ~~~ + # + # Require self >= 0 + fun to_bytes(n_bytes: nullable Int): Bytes do + + # If 0, force using at least one byte + if self == 0 and n_bytes == null then n_bytes = 1 + + # Compute the len (log256) + var len = 1 + var max = 256 + var s = self.abs + while s >= max do + len += 1 + max *= 256 + end + + # Two's complement + s = self + if self < 0 then + var ff = 0 + for j in [0..len[ do + ff *= 0x100 + ff += 0xFF + end + + s = ((-self) ^ ff) + 1 + end + + # Cut long values + if n_bytes != null and len > n_bytes then len = n_bytes + + # Allocate the buffer + var cap = n_bytes or else len + var res = new Bytes.with_capacity(cap) + + var filler = if self < 0 then 0xFF else 0 + for i in [0..cap[ do res[i] = filler + + # Fill it starting with the end + var i = cap + var sum = s + while i > cap - len do + i -= 1 + res[i] = sum % 256 + sum /= 256 + end + + return res + end end # A buffer containing Byte-manipulation facilities # # Uses Copy-On-Write when persisted class Bytes - super AbstractArray[Byte] + super AbstractArray[Int] super BytePattern # A CString being a char*, it can be used as underlying representation here. @@ -178,8 +271,8 @@ class Bytes redef fun is_empty do return length == 0 # var b = new Bytes.empty - # b.add 101u8 - # assert b[0] == 101u8 + # b.add 101 + # assert b[0] == 101 redef fun [](i) do assert i >= 0 assert i < length @@ -202,13 +295,13 @@ class Bytes fun trim: Bytes do var st = 0 while st < length do - if self[st] > 0x20u8 then break + if self[st] > 0x20 then break st += 1 end if st >= length then return new Bytes.empty var ed = length - 1 while ed > 0 do - if self[ed] > 0x20u8 then break + if self[ed] > 0x20 then break ed -= 1 end return slice(st, ed - st + 1) @@ -251,6 +344,21 @@ class Bytes return slice(from, length) end + # Reverse the byte array in place + # + # var b = "abcd".to_bytes + # b.reverse + # assert b.to_s == "dcba" + fun reverse + do + var l = length + for i in [0..l/2[ do + var tmp = self[i] + self[i] = self[l-i-1] + self[l-i-1] = tmp + end + end + # Returns self as an hexadecimal digest. # # Also known as plain hexdump or postscript hexdump. @@ -289,8 +397,8 @@ class Bytes var i = 0 var oi = 0 while i < length do - ns[oi] = 0x5Cu8 # b'\\' - ns[oi+1] = 0x78u8 # b'x' + ns[oi] = u'\\' + ns[oi+1] = u'x' self[i].add_digest_at(ns, oi+2) i += 1 oi += 4 @@ -313,12 +421,12 @@ class Bytes var oi = 0 while i < length do var c = self[i] - var b = 128u8 - while b > 0u8 do - if c & b == 0u8 then - ns[oi] = 0x30u8 # b'0' + var b = 128 + while b > 0 do + if c & b == 0 then + ns[oi] = u'0' else - ns[oi] = 0x31u8 # b'1' + ns[oi] = u'1' end oi += 1 b = b >> 1 @@ -379,7 +487,7 @@ class Bytes end # Two's complement is `signed` - if signed == true and not_empty and first > 0x80u8 then + if signed == true and not_empty and first > 0x80 then var ff = 0 for j in [0..length[ do ff *= 0x100 @@ -393,7 +501,7 @@ class Bytes end # var b = new Bytes.with_capacity(1) - # b[0] = 101u8 + # b[0] = 101 # assert b.to_s == "e" redef fun []=(i, v) do if persisted then regen @@ -404,7 +512,7 @@ class Bytes end # var b = new Bytes.empty - # b.add 101u8 + # b.add 101 # assert b.to_s == "e" redef fun add(c) do if persisted then regen @@ -431,7 +539,7 @@ class Bytes end # var b = new Bytes.empty - # b.append([104u8, 101u8, 108u8, 108u8, 111u8]) + # b.append([104, 101, 108, 108, 111]) # assert b.to_s == "hello" redef fun append(arr) do if arr isa Bytes then @@ -442,7 +550,7 @@ class Bytes end # var b = new Bytes.empty - # b.append([0x41u8, 0x41u8, 0x18u8]) + # b.append([0x41, 0x41, 0x18]) # b.pop # assert b.to_s == "AA" redef fun pop do @@ -541,7 +649,7 @@ class Bytes # Splits the content on self when encountering `b` # - # var a = "String is string".to_bytes.split_with('s'.ascii) + # var a = "String is string".to_bytes.split_with(u's') # assert a.length == 3 # assert a[0].hexdigest == "537472696E672069" # assert a[1].hexdigest == "20" @@ -561,7 +669,7 @@ class Bytes # Splits `self` in two parts at the first occurence of `b` # - # var a = "String is string".to_bytes.split_once_on('s'.ascii) + # var a = "String is string".to_bytes.split_once_on(u's') # assert a[0].hexdigest == "537472696E672069" # assert a[1].hexdigest == "20737472696E67" fun split_once_on(b: BytePattern): Array[Bytes] do @@ -575,7 +683,7 @@ class Bytes # Replaces all the occurences of `this` in `self` by `by` # - # var b = "String is string".to_bytes.replace(0x20u8, 0x41u8) + # var b = "String is string".to_bytes.replace(0x20, 0x41) # assert b.hexdigest == "537472696E6741697341737472696E67" fun replace(pattern: BytePattern, bytes: BytePattern): Bytes do if is_empty then return new Bytes.empty @@ -609,20 +717,20 @@ class Bytes var pos = 0 while pos < length do var b = self[pos] - if b != '%'.ascii then + if b != u'%' then tmp.add b pos += 1 continue end if length - pos < 2 then - tmp.add '%'.ascii + tmp.add u'%' pos += 1 continue end var bn = self[pos + 1] var bnn = self[pos + 2] if not bn.is_valid_hexdigit or not bnn.is_valid_hexdigit then - tmp.add '%'.ascii + tmp.add u'%' pos += 1 continue end @@ -658,7 +766,7 @@ class Bytes end private class BytesIterator - super IndexedIterator[Byte] + super IndexedIterator[Int] var tgt: CString @@ -675,107 +783,12 @@ private class BytesIterator redef fun item do return tgt[index] end -redef class Int - # A signed big-endian representation of `self` - # - # ~~~ - # assert 1.to_bytes.hexdigest == "01" - # assert 255.to_bytes.hexdigest == "FF" - # assert 256.to_bytes.hexdigest == "0100" - # assert 65535.to_bytes.hexdigest == "FFFF" - # assert 65536.to_bytes.hexdigest == "010000" - # ~~~ - # - # Negative values are converted to their two's complement. - # Be careful as the result can be ambiguous. - # - # ~~~ - # assert (-1).to_bytes.hexdigest == "FF" - # assert (-32).to_bytes.hexdigest == "E0" - # assert (-512).to_bytes.hexdigest == "FE00" - # assert (-65794).to_bytes.hexdigest == "FEFEFE" - # ~~~ - # - # Optionally, set `n_bytes` to the desired number of bytes in the output. - # This setting can disambiguate the result between positive and negative - # integers. Be careful with this parameter as the result may overflow. - # - # ~~~ - # assert 1.to_bytes(2).hexdigest == "0001" - # assert 65535.to_bytes(2).hexdigest == "FFFF" - # assert (-1).to_bytes(2).hexdigest == "FFFF" - # assert (-512).to_bytes(4).hexdigest == "FFFFFE00" - # assert 0x123456.to_bytes(2).hexdigest == "3456" - # ~~~ - # - # For 0, a Bytes object with single nul byte is returned (instead of an empty Bytes object). - # - # ~~~ - # assert 0.to_bytes.hexdigest == "00" - # ~~~ - # - # For positive integers, `Bytes::to_i` can reverse the operation. - # - # ~~~ - # assert 1234.to_bytes.to_i == 1234 - # ~~~ - # - # Require self >= 0 - fun to_bytes(n_bytes: nullable Int): Bytes do - - # If 0, force using at least one byte - if self == 0 and n_bytes == null then n_bytes = 1 - - # Compute the len (log256) - var len = 1 - var max = 256 - var s = self.abs - while s >= max do - len += 1 - max *= 256 - end - - # Two's complement - s = self - if self < 0 then - var ff = 0 - for j in [0..len[ do - ff *= 0x100 - ff += 0xFF - end - - s = ((-self) ^ ff) + 1 - end - - # Cut long values - if n_bytes != null and len > n_bytes then len = n_bytes - - # Allocate the buffer - var cap = n_bytes or else len - var res = new Bytes.with_capacity(cap) - - var filler = if self < 0 then 0xFFu8 else 0u8 - for i in [0..cap[ do res[i] = filler - - # Fill it starting with the end - var i = cap - var sum = s - while i > cap - len do - i -= 1 - res[i] = (sum % 256).to_b - sum /= 256 - end - - return res - end -end - redef class Text # Returns a mutable copy of `self`'s bytes # # ~~~nit # assert "String".to_bytes isa Bytes - # assert "String".to_bytes == [83u8, 116u8, 114u8, 105u8, 110u8, 103u8] + # assert "String".to_bytes == [83, 116, 114, 105, 110, 103] # ~~~ fun to_bytes: Bytes do var b = new Bytes.with_capacity(byte_length) @@ -802,7 +815,7 @@ redef class Text # Returns a new `Bytes` instance with the digest as content # - # assert "0B1F4D".hexdigest_to_bytes == [0x0Bu8, 0x1Fu8, 0x4Du8] + # assert "0B1F4D".hexdigest_to_bytes == [0x0B, 0x1F, 0x4D] # assert "0B1F4D".hexdigest_to_bytes.hexdigest == "0B1F4D" # # Characters that are not hexadecimal digits are ignored. @@ -837,7 +850,7 @@ redef class Text var ret = new Bytes.with_capacity((dlength+1) / 2) var i = (dlength+1) % 2 # current hex digit (1=high, 0=low) - var byte = 0u8 # current accumulated byte value + var byte = 0 # current accumulated byte value pos = 0 while pos < max do @@ -849,7 +862,7 @@ redef class Text # Last digit known: store and restart ret.add byte i = 1 - byte = 0u8 + byte = 0 end end pos += 1 @@ -907,7 +920,7 @@ redef class Text else if c == 'x' or c == 'X' then var hx = substring(i + 1, 2) if hx.is_hex then - res.add(hx.to_hex.to_b) + res.add hx.to_hex else res.add_char(c) end @@ -960,23 +973,23 @@ redef class Text while pos < max do var c = b[pos] pos += 1 - if c == 0x30u8 or c == 0x31u8 then bitlen += 1 # b'0' or b'1' + if c == u'0' or c == u'1' then bitlen += 1 end # Allocate (and take care of the padding) var ret = new Bytes.with_capacity((bitlen+7) / 8) var i = (bitlen+7) % 8 # current bit (7th=128, 0th=1) - var byte = 0u8 # current accumulated byte value + var byte = 0 # current accumulated byte value pos = 0 while pos < max do var c = b[pos] pos += 1 - if c == 0x30u8 then # b'0' + if c == u'0' then byte = byte << 1 - else if c == 0x31u8 then # b'1' - byte = byte << 1 | 1u8 + else if c == u'1' then + byte = byte << 1 | 1 else continue end @@ -986,7 +999,7 @@ redef class Text # Last bit known: store and restart ret.add byte i = 7 - byte = 0u8 + byte = 0 end end return ret @@ -1022,7 +1035,7 @@ end # Joins an array of bytes `arr` separated by `sep` # -# assert join_bytes(["String".to_bytes, "is".to_bytes, "string".to_bytes], ' '.ascii).hexdigest == "537472696E6720697320737472696E67" +# assert join_bytes(["String".to_bytes, "is".to_bytes, "string".to_bytes], u' ').hexdigest == "537472696E6720697320737472696E67" fun join_bytes(arr: Array[Bytes], sep: nullable BytePattern): Bytes do if arr.is_empty then return new Bytes.empty sep = sep or else new Bytes.empty diff --git a/lib/core/codecs/iso8859_1.nit b/lib/core/codecs/iso8859_1.nit index 005c569..be52242 100644 --- a/lib/core/codecs/iso8859_1.nit +++ b/lib/core/codecs/iso8859_1.nit @@ -35,7 +35,7 @@ private class ISO88591Codec redef fun add_char_to(c, stream) do var cp = if c.code_point <= 255 then c else '?' - stream[0] = cp.ascii + stream[0] = cp.code_point return 1 end @@ -50,9 +50,9 @@ private class ISO88591Codec for i in s.chars do var cp = i.code_point if cp <= 255 then - b[pos] = cp.to_b + b[pos] = cp else - b[pos] = 0x3Fu8 + b[pos] = 0x3F end pos += 1 end diff --git a/lib/core/codecs/utf8.nit b/lib/core/codecs/utf8.nit index d4d4a38..c37bd35 100644 --- a/lib/core/codecs/utf8.nit +++ b/lib/core/codecs/utf8.nit @@ -54,7 +54,7 @@ private class UTF8Codec redef fun is_valid_char(ns, len) do if len == 0 then return 2 if not ns[0].is_valid_utf8_start then return 2 - for i in [1 .. len[ do if ns[i] & 0b1100_0000u8 != 0b1000_0000u8 then return 2 + for i in [1 .. len[ do if ns[i] & 0b1100_0000 != 0b1000_0000 then return 2 if len != ns[0].u8len then return 1 return 0 end diff --git a/lib/core/collection/abstract_collection.nit b/lib/core/collection/abstract_collection.nit index 04dabfa..b51cd22 100644 --- a/lib/core/collection/abstract_collection.nit +++ b/lib/core/collection/abstract_collection.nit @@ -396,6 +396,7 @@ interface SimpleCollection[E] fun add(item: E) is abstract # Add each item of `coll`. + # # var a = [1,2] # a.add_all([3..5]) # assert a.has(4) == true diff --git a/lib/core/collection/union_find.nit b/lib/core/collection/union_find.nit index 80c5005..864c509 100644 --- a/lib/core/collection/union_find.nit +++ b/lib/core/collection/union_find.nit @@ -140,6 +140,7 @@ class DisjointSet[E] end # Are all elements of `es` in the same subset? + # # var s = new DisjointSet[Int] # s.add_all([1,2,3,4,5,6]) # s.union_all([1,2,3]) diff --git a/lib/core/core.nit b/lib/core/core.nit index 54f2550..5261077 100644 --- a/lib/core/core.nit +++ b/lib/core/core.nit @@ -15,7 +15,6 @@ # This module is implicitly imported by every module. module core -import posix import environ import time import file diff --git a/lib/core/file.nit b/lib/core/file.nit index 26f7398..ed4c6c8 100644 --- a/lib/core/file.nit +++ b/lib/core/file.nit @@ -306,6 +306,9 @@ redef class Int private fun fd_to_stream(mode: CString): NativeFile `{ return fdopen((int)self, mode); `} + + # Does the file descriptor `self` refer to a terminal? + fun isatty: Bool `{ return isatty(self); `} end # Constant for read-only file streams @@ -1362,7 +1365,7 @@ redef class FlatString var p = last_byte var c = its[p] var st = _first_byte - while p >= st and c != '.'.ascii do + while p >= st and c != u'.' do p -= 1 c = its[p] end @@ -1379,7 +1382,7 @@ redef class FlatString var l = s.last_byte var its = s._items var min = s._first_byte - var sl = '/'.ascii + var sl = u'/' while l > min and its[l] == sl do l -= 1 if l == min then return "/" var ns = l @@ -1523,7 +1526,7 @@ private extern class NativeFile `{ FILE* `} return (long)res; `} - fun write_byte(value: Byte): Int `{ + fun write_byte(value: Int): Int `{ unsigned char b = (unsigned char)value; return fwrite(&b, 1, 1, self); `} diff --git a/lib/core/fixed_ints.nit b/lib/core/fixed_ints.nit index ce79f53..521c02b 100644 --- a/lib/core/fixed_ints.nit +++ b/lib/core/fixed_ints.nit @@ -158,9 +158,6 @@ universal Int8 redef fun to_i32 is intern redef fun to_u32 is intern - # Returns `self` as a Char according to its ASCII value. - fun ascii: Char `{ return (uint32_t)self; `} - redef fun distance(i) do return (self - i).to_i redef fun <=>(other) @@ -252,9 +249,6 @@ universal Int16 redef fun *(i) is intern redef fun /(i) is intern - # Returns `self` as a Char according to its ASCII value. - fun ascii: Char `{ return (uint32_t)self; `} - # Modulo of `self` with `i`. # # Returns the remainder of division of `self` by `i`. @@ -387,9 +381,6 @@ universal UInt16 redef fun zero do return 0.to_u16 redef fun value_of(val) do return val.to_u16 - # Returns `self` as a Char according to its ASCII value. - fun ascii: Char `{ return (uint32_t)self; `} - # `i` bits shift to the left # # assert 5u16 << 1 == 10u16 @@ -500,9 +491,6 @@ universal Int32 redef fun *(i) is intern redef fun /(i) is intern - # Returns `self` as a Char according to its ASCII value. - fun ascii: Char `{ return (uint32_t)self; `} - # Modulo of `self` with `i`. # # Returns the remainder of division of `self` by `i`. @@ -624,9 +612,6 @@ universal UInt32 redef fun *(i) is intern redef fun /(i) is intern - # Returns `self` as a Char according to its ASCII value. - fun ascii: Char `{ return (uint32_t)self; `} - # Modulo of `self` with `i`. # # Returns the remainder of division of `self` by `i`. diff --git a/lib/core/kernel.nit b/lib/core/kernel.nit index 6a07060..39a5958 100644 --- a/lib/core/kernel.nit +++ b/lib/core/kernel.nit @@ -651,11 +651,6 @@ universal Byte # assert 5u8 >> 1 == 2u8 fun >>(i: Int): Byte is intern `{ return self >> i; `} - # Returns the character equivalent of `self` - # - # REQUIRE: `self <= 127u8` - fun ascii: Char is intern `{ return (uint32_t)self; `} - redef fun to_i is intern redef fun to_f is intern redef fun to_b do return self @@ -863,8 +858,11 @@ universal Int # Return the corresponding digit character # If 0 <= `self` <= 9, return the corresponding character. + # # assert 5.to_c == '5' + # # If 10 <= `self` <= 36, return the corresponding letter [a..z]. + # # assert 15.to_c == 'f' fun to_c: Char do @@ -882,6 +880,9 @@ universal Int # assert 10.abs == 10 # assert 0.abs == 0 fun abs: Int do return if self >= 0 then self else -self + + # Is `self` an ASCII whitespace ? + fun is_whitespace: Bool do return self == 0x7F or self <= 0x20 end # Native characters. @@ -918,6 +919,24 @@ universal Char redef fun successor(i) is intern redef fun predecessor(i) is intern + # The `i`-th char after self (in code point) + # + # ~~~ + # assert 'A' + 5 == 'F' + # ~~~ + # + # Alias of `successor`. + fun +(i: Int): Char do return successor(i) + + # The `i`-th char before self (in code point) + # + # ~~~ + # assert 'F' - 5 == 'A' + # ~~~ + # + # Alias of `predecessor`. + fun -(i: Int): Char do return predecessor(i) + redef fun distance(c) do var d = self.code_point - c.code_point @@ -943,14 +962,6 @@ universal Char end end - # The ascii value of `self` - # - # assert 'a'.ascii == 97u8 - # assert '\n'.ascii == 10u8 - # - # REQUIRE: `is_ascii` - fun ascii: Byte do return code_point.to_b - # The unicode code point value of `self` # # assert 'A'.code_point == 65 diff --git a/lib/core/stream.nit b/lib/core/stream.nit index 3fc3f30..152c294 100644 --- a/lib/core/stream.nit +++ b/lib/core/stream.nit @@ -122,7 +122,7 @@ abstract class Reader for i in [0 .. max[ do var b = raw_read_byte if b < 0 then break - buf[i] = b.to_b + buf[i] = b rd += 1 end return rd @@ -551,7 +551,7 @@ abstract class Writer fun write(s: Text) is abstract # Write a single byte - fun write_byte(value: Byte) is abstract + fun write_byte(value: Int) is abstract # Write a single char fun write_char(c: Char) do @@ -574,17 +574,32 @@ interface Writable # The specific logic it let to the concrete subclasses fun write_to(stream: Writer) is abstract - # Like `write_to` but return a new String (may be quite large) + # Like `write_to` but return a new String (may be quite large). # - # This funtionality is anectodical, since the point - # of streamable object to to be efficienlty written to a - # stream without having to allocate and concatenate strings + # This functionality is anecdotal, since the point + # of a streamable object is to be efficiently written to a + # stream without having to allocate and concatenate strings. fun write_to_string: String do var stream = new StringWriter write_to(stream) return stream.to_s end + + # Like `write_to` but return a new Bytes (may be quite large) + # + # This functionality is anecdotal, since the point + # of a streamable object is to be efficiently written to a + # stream without having to allocate and concatenate buffers. + # + # Nevertheless, you might need this method if you want to know + # the byte size of a writable object. + fun write_to_bytes: Bytes + do + var stream = new BytesWriter + write_to(stream) + return stream.bytes + end end redef class Bytes @@ -612,7 +627,7 @@ end # # writer.write "Strings " # writer.write_char '&' -# writer.write_byte 0x20u8 +# writer.write_byte 0x20 # writer.write_bytes "bytes".to_bytes # # assert writer.to_s == "\\x53\\x74\\x72\\x69\\x6E\\x67\\x73\\x20\\x26\\x20\\x62\\x79\\x74\\x65\\x73" @@ -626,12 +641,12 @@ end # writer = new BytesWriter # # # Write just the character first half -# writer.write_byte 0xC2u8 +# writer.write_byte 0xC2 # assert writer.to_s == "\\xC2" # assert writer.bytes.to_s == "�" # # # Complete the character -# writer.write_byte 0xA2u8 +# writer.write_byte 0xA2 # assert writer.to_s == "\\xC2\\xA2" # assert writer.bytes.to_s == "¢" # ~~~ @@ -683,7 +698,7 @@ end # # writer.write "Strings " # writer.write_char '&' -# writer.write_byte 0x20u8 +# writer.write_byte 0x20 # writer.write_bytes "bytes".to_bytes # # assert writer.to_s == "Strings & bytes" diff --git a/lib/core/text/abstract_text.nit b/lib/core/text/abstract_text.nit index 168225c..fbe045f 100644 --- a/lib/core/text/abstract_text.nit +++ b/lib/core/text/abstract_text.nit @@ -34,34 +34,44 @@ abstract class Text # Gets a view on the chars of the Text object # - # assert "hello".chars.to_a == ['h', 'e', 'l', 'l', 'o'] + # ~~~ + # assert "hello".chars.to_a == ['h', 'e', 'l', 'l', 'o'] + # ~~~ fun chars: SequenceRead[Char] is abstract # Gets a view on the bytes of the Text object # - # assert "hello".bytes.to_a == [104u8, 101u8, 108u8, 108u8, 111u8] - fun bytes: SequenceRead[Byte] is abstract + # ~~~ + # assert "hello".bytes.to_a == [104, 101, 108, 108, 111] + # ~~~ + fun bytes: SequenceRead[Int] is abstract # Number of characters contained in self. # - # assert "12345".length == 5 - # assert "".length == 0 - # assert "あいうえお".length == 5 + # ~~~ + # assert "12345".length == 5 + # assert "".length == 0 + # assert "あいうえお".length == 5 + # ~~~ fun length: Int is abstract # Number of bytes in `self` # - # assert "12345".byte_length == 5 - # assert "あいうえお".byte_length == 15 + # ~~~ + # assert "12345".byte_length == 5 + # assert "あいうえお".byte_length == 15 + # ~~~ fun byte_length: Int is abstract # Create a substring. # - # assert "abcd".substring(1, 2) == "bc" - # assert "abcd".substring(-1, 2) == "a" - # assert "abcd".substring(1, 0) == "" - # assert "abcd".substring(2, 5) == "cd" - # assert "あいうえお".substring(1,3) == "いうえ" + # ~~~ + # assert "abcd".substring(1, 2) == "bc" + # assert "abcd".substring(-1, 2) == "a" + # assert "abcd".substring(1, 0) == "" + # assert "abcd".substring(2, 5) == "cd" + # assert "あいうえお".substring(1,3) == "いうえ" + # ~~~ # # A `from` index < 0 will be replaced by 0. # Unless a `count` value is > 0 at the same time. @@ -73,8 +83,10 @@ abstract class Text # Is the current Text empty (== "") # - # assert "".is_empty - # assert not "foo".is_empty + # ~~~ + # assert "".is_empty + # assert not "foo".is_empty + # ~~~ fun is_empty: Bool do return self.length == 0 # Returns an empty Text of the right type @@ -87,37 +99,29 @@ abstract class Text fun to_buffer: Buffer is abstract # Gets the first char of the Text - # - # DEPRECATED : Use self.chars.first instead fun first: Char do return self.chars[0] # Access a character at `index` in the string. # - # assert "abcd"[2] == 'c' - # - # DEPRECATED : Use self.chars.[] instead + # ~~~ + # assert "abcd"[2] == 'c' + # ~~~ fun [](index: Int): Char do return self.chars[index] # Gets the index of the first occurence of 'c' # # Returns -1 if not found - # - # DEPRECATED : Use self.chars.index_of instead fun index_of(c: Char): Int do return index_of_from(c, 0) end # Gets the last char of self - # - # DEPRECATED : Use self.chars.last instead fun last: Char do return self.chars[length-1] # Gets the index of the first occurence of ´c´ starting from ´pos´ # # Returns -1 if not found - # - # DEPRECATED : Use self.chars.index_of_from instead fun index_of_from(c: Char, pos: Int): Int do var iter = self.chars.iterator_from(pos) @@ -131,8 +135,6 @@ abstract class Text # Gets the last index of char ´c´ # # Returns -1 if not found - # - # DEPRECATED : Use self.chars.last_index_of instead fun last_index_of(c: Char): Int do return last_index_of_from(c, length - 1) @@ -143,24 +145,24 @@ abstract class Text # The index of the last occurrence of an element starting from pos (in reverse order). # - # var s = "/etc/bin/test/test.nit" - # assert s.last_index_of_from('/', s.length-1) == 13 - # assert s.last_index_of_from('/', 12) == 8 + # ~~~ + # var s = "/etc/bin/test/test.nit" + # assert s.last_index_of_from('/', s.length-1) == 13 + # assert s.last_index_of_from('/', 12) == 8 + # ~~~ # # Returns -1 if not found - # - # DEPRECATED : Use self.chars.last_index_of_from instead fun last_index_of_from(item: Char, pos: Int): Int do return chars.last_index_of_from(item, pos) # Concatenates `o` to `self` # - # assert "hello" + "world" == "helloworld" - # assert "" + "hello" + "" == "hello" + # ~~~ + # assert "hello" + "world" == "helloworld" + # assert "" + "hello" + "" == "hello" + # ~~~ fun +(o: Text): SELFTYPE is abstract # Gets an iterator on the chars of self - # - # DEPRECATED : Use self.chars.iterator instead fun iterator: Iterator[Char] do return self.chars.iterator @@ -168,15 +170,15 @@ abstract class Text # Gets an Array containing the chars of self - # - # DEPRECATED : Use self.chars.to_a instead fun to_a: Array[Char] do return chars.to_a # Create a substring from `self` beginning at the `from` position # - # assert "abcd".substring_from(1) == "bcd" - # assert "abcd".substring_from(-1) == "abcd" - # assert "abcd".substring_from(2) == "cd" + # ~~~ + # assert "abcd".substring_from(1) == "bcd" + # assert "abcd".substring_from(-1) == "abcd" + # assert "abcd".substring_from(2) == "cd" + # ~~~ # # As with substring, a `from` index < 0 will be replaced by 0 fun substring_from(from: Int): SELFTYPE @@ -188,8 +190,10 @@ abstract class Text # Does self have a substring `str` starting from position `pos`? # - # assert "abcd".has_substring("bc",1) == true - # assert "abcd".has_substring("bc",2) == false + # ~~~ + # assert "abcd".has_substring("bc",1) == true + # assert "abcd".has_substring("bc",2) == false + # ~~~ # # Returns true iff all characters of `str` are presents # at the expected index in `self.` @@ -198,13 +202,17 @@ abstract class Text # # This means that all characters of `str` need to be inside `self`. # - # assert "abcd".has_substring("xab", -1) == false - # assert "abcd".has_substring("cdx", 2) == false + # ~~~ + # assert "abcd".has_substring("xab", -1) == false + # assert "abcd".has_substring("cdx", 2) == false + # ~~~ # # And that the empty string is always a valid substring. # - # assert "abcd".has_substring("", 2) == true - # assert "abcd".has_substring("", 200) == true + # ~~~ + # assert "abcd".has_substring("", 2) == true + # assert "abcd".has_substring("", 200) == true + # ~~~ fun has_substring(str: String, pos: Int): Bool do if str.is_empty then return true @@ -222,33 +230,41 @@ abstract class Text # Is this string prefixed by `prefix`? # - # assert "abcd".has_prefix("ab") == true - # assert "abcbc".has_prefix("bc") == false - # assert "ab".has_prefix("abcd") == false + # ~~~ + # assert "abcd".has_prefix("ab") == true + # assert "abcbc".has_prefix("bc") == false + # assert "ab".has_prefix("abcd") == false + # ~~~ fun has_prefix(prefix: String): Bool do return has_substring(prefix,0) # Is this string suffixed by `suffix`? # - # assert "abcd".has_suffix("abc") == false - # assert "abcd".has_suffix("bcd") == true + # ~~~ + # assert "abcd".has_suffix("abc") == false + # assert "abcd".has_suffix("bcd") == true + # ~~~ fun has_suffix(suffix: String): Bool do return has_substring(suffix, length - suffix.length) # Returns `self` as the corresponding integer # - # assert "123".to_i == 123 - # assert "-1".to_i == -1 - # assert "0x64".to_i == 100 - # assert "0b1100_0011".to_i== 195 - # assert "--12".to_i == 12 + # ~~~ + # assert "123".to_i == 123 + # assert "-1".to_i == -1 + # assert "0x64".to_i == 100 + # assert "0b1100_0011".to_i== 195 + # assert "--12".to_i == 12 + # ~~~ # # REQUIRE: `self`.`is_int` fun to_i: Int is abstract # If `self` contains a float, return the corresponding float # - # assert "123".to_f == 123.0 - # assert "-1".to_f == -1.0 - # assert "-1.2e-3".to_f == -0.0012 + # ~~~ + # assert "123".to_f == 123.0 + # assert "-1".to_f == -1.0 + # assert "-1.2e-3".to_f == -0.0012 + # ~~~ fun to_f: Float do # Shortcut @@ -257,7 +273,9 @@ abstract class Text # If `self` contains only digits and alpha <= 'f', return the corresponding integer. # - # assert "ff".to_hex == 255 + # ~~~ + # assert "ff".to_hex == 255 + # ~~~ fun to_hex(pos, ln: nullable Int): Int do var res = 0 if pos == null then pos = 0 @@ -272,22 +290,30 @@ abstract class Text # If `self` contains only digits <= '7', return the corresponding integer. # - # assert "714".to_oct == 460 + # ~~~ + # assert "714".to_oct == 460 + # ~~~ fun to_oct: Int do return a_to(8) # If `self` contains only '0' et '1', return the corresponding integer. # - # assert "101101".to_bin == 45 + # ~~~ + # assert "101101".to_bin == 45 + # ~~~ fun to_bin: Int do return a_to(2) # If `self` contains only digits '0' .. '9', return the corresponding integer. # - # assert "108".to_dec == 108 + # ~~~ + # assert "108".to_dec == 108 + # ~~~ fun to_dec: Int do return a_to(10) # If `self` contains only digits and letters, return the corresponding integer in a given base # - # assert "120".a_to(3) == 15 + # ~~~ + # assert "120".a_to(3) == 15 + # ~~~ fun a_to(base: Int) : Int do var i = 0 @@ -317,12 +343,14 @@ abstract class Text # Is this string in a valid numeric format compatible with `to_f`? # - # assert "123".is_numeric == true - # assert "1.2".is_numeric == true - # assert "-1.2".is_numeric == true - # assert "-1.23e-2".is_numeric == true - # assert "1..2".is_numeric == false - # assert "".is_numeric == false + # ~~~ + # assert "123".is_numeric == true + # assert "1.2".is_numeric == true + # assert "-1.2".is_numeric == true + # assert "-1.23e-2".is_numeric == true + # assert "1..2".is_numeric == false + # assert "".is_numeric == false + # ~~~ fun is_numeric: Bool do var has_point = false @@ -345,9 +373,11 @@ abstract class Text # Returns `true` if the string contains only Hex chars # - # assert "048bf".is_hex == true - # assert "ABCDEF".is_hex == true - # assert "0G".is_hex == false + # ~~~ + # assert "048bf".is_hex == true + # assert "ABCDEF".is_hex == true + # assert "0G".is_hex == false + # ~~~ fun is_hex: Bool do for i in [0..length[ do @@ -361,8 +391,10 @@ abstract class Text # Returns `true` if the string contains only Binary digits # - # assert "1101100".is_bin == true - # assert "1101020".is_bin == false + # ~~~ + # assert "1101100".is_bin == true + # assert "1101020".is_bin == false + # ~~~ fun is_bin: Bool do for i in chars do if i != '0' and i != '1' then return false return true @@ -370,8 +402,10 @@ abstract class Text # Returns `true` if the string contains only Octal digits # - # assert "213453".is_oct == true - # assert "781".is_oct == false + # ~~~ + # assert "213453".is_oct == true + # assert "781".is_oct == false + # ~~~ fun is_oct: Bool do for i in chars do if i < '0' or i > '7' then return false return true @@ -379,8 +413,10 @@ abstract class Text # Returns `true` if the string contains only Decimal digits # - # assert "10839".is_dec == true - # assert "164F".is_dec == false + # ~~~ + # assert "10839".is_dec == true + # assert "164F".is_dec == false + # ~~~ fun is_dec: Bool do for i in chars do if i < '0' or i > '9' then return false return true @@ -388,10 +424,12 @@ abstract class Text # Are all letters in `self` upper-case ? # - # assert "HELLO WORLD".is_upper == true - # assert "%$&%!".is_upper == true - # assert "hello world".is_upper == false - # assert "Hello World".is_upper == false + # ~~~ + # assert "HELLO WORLD".is_upper == true + # assert "%$&%!".is_upper == true + # assert "hello world".is_upper == false + # assert "Hello World".is_upper == false + # ~~~ fun is_upper: Bool do for i in [0..length[ do @@ -403,9 +441,11 @@ abstract class Text # Are all letters in `self` lower-case ? # - # assert "hello world".is_lower == true - # assert "%$&%!".is_lower == true - # assert "Hello World".is_lower == false + # ~~~ + # assert "hello world".is_lower == true + # assert "%$&%!".is_lower == true + # assert "Hello World".is_lower == false + # ~~~ fun is_lower: Bool do for i in [0..length[ do @@ -417,7 +457,9 @@ abstract class Text # Removes the whitespaces at the beginning of self # - # assert " \n\thello \n\t".l_trim == "hello \n\t" + # ~~~ + # assert " \n\thello \n\t".l_trim == "hello \n\t" + # ~~~ # # `Char::is_whitespace` determines what is a whitespace. fun l_trim: SELFTYPE @@ -433,7 +475,9 @@ abstract class Text # Removes the whitespaces at the end of self # - # assert " \n\thello \n\t".r_trim == " \n\thello" + # ~~~ + # assert " \n\thello \n\t".r_trim == " \n\thello" + # ~~~ # # `Char::is_whitespace` determines what is a whitespace. fun r_trim: SELFTYPE @@ -449,17 +493,21 @@ abstract class Text # Trims trailing and preceding white spaces # - # assert " Hello World ! ".trim == "Hello World !" - # assert "\na\nb\tc\t".trim == "a\nb\tc" + # ~~~ + # assert " Hello World ! ".trim == "Hello World !" + # assert "\na\nb\tc\t".trim == "a\nb\tc" + # ~~~ # # `Char::is_whitespace` determines what is a whitespace. fun trim: SELFTYPE do return (self.l_trim).r_trim # Is the string non-empty but only made of whitespaces? # - # assert " \n\t ".is_whitespace == true - # assert " hello ".is_whitespace == false - # assert "".is_whitespace == false + # ~~~ + # assert " \n\t ".is_whitespace == true + # assert " hello ".is_whitespace == false + # assert "".is_whitespace == false + # ~~~ # # `Char::is_whitespace` determines what is a whitespace. fun is_whitespace: Bool @@ -473,19 +521,23 @@ abstract class Text # Returns `self` removed from its last line terminator (if any). # - # assert "Hello\n".chomp == "Hello" - # assert "Hello".chomp == "Hello" + # ~~~ + # assert "Hello\n".chomp == "Hello" + # assert "Hello".chomp == "Hello" # - # assert "\n".chomp == "" - # assert "".chomp == "" + # assert "\n".chomp == "" + # assert "".chomp == "" + # ~~~ # # Line terminators are `"\n"`, `"\r\n"` and `"\r"`. # A single line terminator, the last one, is removed. # - # assert "\r\n".chomp == "" - # assert "\r\n\n".chomp == "\r\n" - # assert "\r\n\r\n".chomp == "\r\n" - # assert "\r\n\r".chomp == "\r\n" + # ~~~ + # assert "\r\n".chomp == "" + # assert "\r\n\n".chomp == "\r\n" + # assert "\r\n\r\n".chomp == "\r\n" + # assert "\r\n\r".chomp == "\r\n" + # ~~~ # # Note: unlike with most IO methods like `Reader::read_line`, # a single `\r` is considered here to be a line terminator and will be removed. @@ -516,14 +568,18 @@ abstract class Text # # Examples # - # assert "hello".justify(10, 0.0) == "hello " - # assert "hello".justify(10, 1.0) == " hello" - # assert "hello".justify(10, 0.5) == " hello " - # assert "hello".justify(10, 0.5, '.') == "..hello..." + # ~~~ + # assert "hello".justify(10, 0.0) == "hello " + # assert "hello".justify(10, 1.0) == " hello" + # assert "hello".justify(10, 0.5) == " hello " + # assert "hello".justify(10, 0.5, '.') == "..hello..." + # ~~~ # # If `length` is not enough, `self` is returned as is. # - # assert "hello".justify(2, 0.0) == "hello" + # ~~~ + # assert "hello".justify(2, 0.0) == "hello" + # ~~~ # # REQUIRE: `left >= 0.0 and left <= 1.0` # ENSURE: `self.length <= length implies result.length == length` @@ -548,13 +604,17 @@ abstract class Text # * Never ends with an underscore. # * Never contains two contiguous underscores. # - # assert "42_is/The answer!".to_cmangle == "_52d2_is_47dThe_32danswer_33d" - # assert "__".to_cmangle == "_95d_95d" - # assert "__d".to_cmangle == "_95d_d" - # assert "_d_".to_cmangle == "_d_95d" - # assert "_42".to_cmangle == "_95d42" - # assert "foo".to_cmangle == "foo" - # assert "".to_cmangle == "" + # Examples: + # + # ~~~ + # assert "42_is/The answer!".to_cmangle == "_52d2_is_47dThe_32danswer_33d" + # assert "__".to_cmangle == "_95d_95d" + # assert "__d".to_cmangle == "_95d_d" + # assert "_d_".to_cmangle == "_d_95d" + # assert "_42".to_cmangle == "_95d42" + # assert "foo".to_cmangle == "foo" + # assert "".to_cmangle == "" + # ~~~ fun to_cmangle: String do if is_empty then return "" @@ -602,17 +662,21 @@ abstract class Text # Escape `"` `\` `'`, trigraphs and non printable characters using the rules of literal C strings and characters # - # assert "abAB12<>&".escape_to_c == "abAB12<>&" - # assert "\n\"'\\".escape_to_c == "\\n\\\"\\'\\\\" - # assert "allo???!".escape_to_c == "allo??\\?!" - # assert "??=??/??'??(??)".escape_to_c == "?\\?=?\\?/??\\'?\\?(?\\?)" - # assert "??!????-".escape_to_c == "?\\?!?\\??\\?-" + # ~~~ + # assert "abAB12<>&".escape_to_c == "abAB12<>&" + # assert "\n\"'\\".escape_to_c == "\\n\\\"\\'\\\\" + # assert "allo???!".escape_to_c == "allo??\\?!" + # assert "??=??/??'??(??)".escape_to_c == "?\\?=?\\?/??\\'?\\?(?\\?)" + # assert "??!????-".escape_to_c == "?\\?!?\\??\\?-" + # ~~~ # # Most non-printable characters (bellow ASCII 32) are escaped to an octal form `\nnn`. # Three digits are always used to avoid following digits to be interpreted as an element # of the octal sequence. # - # assert "{0.code_point}{1.code_point}{8.code_point}{31.code_point}{32.code_point}".escape_to_c == "\\000\\001\\010\\037 " + # ~~~ + # assert "{0.code_point}{1.code_point}{8.code_point}{31.code_point}{32.code_point}".escape_to_c == "\\000\\001\\010\\037 " + # ~~~ # # The exceptions are the common `\t` and `\n`. fun escape_to_c: String @@ -670,8 +734,10 @@ abstract class Text # Escape additionnal characters # The result might no be legal in C but be used in other languages # - # assert "ab|\{\}".escape_more_to_c("|\{\}") == "ab\\|\\\{\\\}" - # assert "allo???!".escape_more_to_c("") == "allo??\\?!" + # ~~~ + # assert "ab|\{\}".escape_more_to_c("|\{\}") == "ab\\|\\\{\\\}" + # assert "allo???!".escape_more_to_c("") == "allo??\\?!" + # ~~~ fun escape_more_to_c(chars: String): String do var b = new Buffer @@ -686,14 +752,18 @@ abstract class Text # Escape to C plus braces # - # assert "\n\"'\\\{\}".escape_to_nit == "\\n\\\"\\'\\\\\\\{\\\}" + # ~~~ + # assert "\n\"'\\\{\}".escape_to_nit == "\\n\\\"\\'\\\\\\\{\\\}" + # ~~~ fun escape_to_nit: String do return escape_more_to_c("\{\}") # Escape to POSIX Shell (sh). # # Abort if the text contains a null byte. # - # assert "\n\"'\\\{\}0".escape_to_sh == "'\n\"'\\''\\\{\}0'" + # ~~~ + # assert "\n\"'\\\{\}0".escape_to_sh == "'\n\"'\\''\\\{\}0'" + # ~~~ fun escape_to_sh: String do var b = new Buffer b.chars.add '\'' @@ -724,7 +794,7 @@ abstract class Text else if c == ':' or c == ' ' or c == '#' then b.add('\\') b.add(c) - else if c.code_point < 32 or c == ';' or c == '|' or c == '\\' or c == '=' then + else if c.code_point < 32 or c == ';' or c == '|' or c == '\\' then b.append("?{c.code_point.to_base(16)}") else b.add(c) @@ -735,11 +805,13 @@ abstract class Text # Return a string where Nit escape sequences are transformed. # - # var s = "\\n" - # assert s.length == 2 - # var u = s.unescape_nit - # assert u.length == 1 - # assert u.chars[0].code_point == 10 # (the ASCII value of the "new line" character) + # ~~~ + # var s = "\\n" + # assert s.length == 2 + # var u = s.unescape_nit + # assert u.length == 1 + # assert u.chars[0].code_point == 10 # (the ASCII value of the "new line" character) + # ~~~ fun unescape_nit: String do var res = new Buffer.with_cap(self.length) @@ -772,7 +844,9 @@ abstract class Text # Returns `self` with all characters escaped with their UTF-16 representation # - # assert "Aèあ𐏓".escape_to_utf16 == "\\u0041\\u00e8\\u3042\\ud800\\udfd3" + # ~~~ + # assert "Aèあ𐏓".escape_to_utf16 == "\\u0041\\u00e8\\u3042\\ud800\\udfd3" + # ~~~ fun escape_to_utf16: String do var buf = new Buffer for i in chars do buf.append i.escape_to_utf16 @@ -781,10 +855,12 @@ abstract class Text # Returns the Unicode char escaped by `self` # - # assert "\\u0041".from_utf16_escape == 'A' - # assert "\\ud800\\udfd3".from_utf16_escape == '𐏓' - # assert "\\u00e8".from_utf16_escape == 'è' - # assert "\\u3042".from_utf16_escape == 'あ' + # ~~~ + # assert "\\u0041".from_utf16_escape == 'A' + # assert "\\ud800\\udfd3".from_utf16_escape == '𐏓' + # assert "\\u00e8".from_utf16_escape == 'è' + # assert "\\u3042".from_utf16_escape == 'あ' + # ~~~ fun from_utf16_escape(pos, ln: nullable Int): Char do if pos == null then pos = 0 if ln == null then ln = length - pos @@ -805,9 +881,11 @@ abstract class Text # Returns a UTF-16 escape value # - # var s = "\\ud800\\udfd3" - # assert s.from_utf16_digit(2) == 0xD800 - # assert s.from_utf16_digit(8) == 0xDFD3 + # ~~~ + # var s = "\\ud800\\udfd3" + # assert s.from_utf16_digit(2) == 0xD800 + # assert s.from_utf16_digit(8) == 0xDFD3 + # ~~~ fun from_utf16_digit(pos: nullable Int): Int do if pos == null then pos = 0 return to_hex(pos, 4) @@ -815,10 +893,12 @@ abstract class Text # Encode `self` to percent (or URL) encoding # - # assert "aBc09-._~".to_percent_encoding == "aBc09-._~" - # assert "%()< >".to_percent_encoding == "%25%28%29%3c%20%3e" - # assert ".com/post?e=asdf&f=123".to_percent_encoding == ".com%2fpost%3fe%3dasdf%26f%3d123" - # assert "éあいう".to_percent_encoding == "%c3%a9%e3%81%82%e3%81%84%e3%81%86" + # ~~~ + # assert "aBc09-._~".to_percent_encoding == "aBc09-._~" + # assert "%()< >".to_percent_encoding == "%25%28%29%3c%20%3e" + # assert ".com/post?e=asdf&f=123".to_percent_encoding == ".com%2fpost%3fe%3dasdf%26f%3d123" + # assert "éあいう".to_percent_encoding == "%c3%a9%e3%81%82%e3%81%84%e3%81%86" + # ~~~ fun to_percent_encoding: String do var buf = new Buffer @@ -845,14 +925,16 @@ abstract class Text # # Invalid '%' are not decoded. # - # assert "aBc09-._~".from_percent_encoding == "aBc09-._~" - # assert "%25%28%29%3c%20%3e".from_percent_encoding == "%()< >" - # assert ".com%2fpost%3fe%3dasdf%26f%3d123".from_percent_encoding == ".com/post?e=asdf&f=123" - # assert "%25%28%29%3C%20%3E".from_percent_encoding == "%()< >" - # assert "incomplete %".from_percent_encoding == "incomplete %" - # assert "invalid % usage".from_percent_encoding == "invalid % usage" - # assert "%c3%a9%e3%81%82%e3%81%84%e3%81%86".from_percent_encoding == "éあいう" - # assert "%1 %A %C3%A9A9".from_percent_encoding == "%1 %A éA9" + # ~~~ + # assert "aBc09-._~".from_percent_encoding == "aBc09-._~" + # assert "%25%28%29%3c%20%3e".from_percent_encoding == "%()< >" + # assert ".com%2fpost%3fe%3dasdf%26f%3d123".from_percent_encoding == ".com/post?e=asdf&f=123" + # assert "%25%28%29%3C%20%3E".from_percent_encoding == "%()< >" + # assert "incomplete %".from_percent_encoding == "incomplete %" + # assert "invalid % usage".from_percent_encoding == "invalid % usage" + # assert "%c3%a9%e3%81%82%e3%81%84%e3%81%86".from_percent_encoding == "éあいう" + # assert "%1 %A %C3%A9A9".from_percent_encoding == "%1 %A éA9" + # ~~~ fun from_percent_encoding: String do var len = byte_length @@ -875,21 +957,21 @@ abstract class Text if c == '%' then if i + 2 >= length then # What follows % has been cut off - buf[l] = '%'.ascii + buf[l] = u'%' else i += 1 var hex_s = substring(i, 2) if hex_s.is_hex then var hex_i = hex_s.to_hex - buf[l] = hex_i.to_b + buf[l] = hex_i i += 1 else # What follows a % is not Hex - buf[l] = '%'.ascii + buf[l] = u'%' i -= 1 end end - else buf[l] = c.ascii + else buf[l] = c.code_point i += 1 l += 1 @@ -900,7 +982,9 @@ abstract class Text # Escape the characters `<`, `>`, `&`, `"`, `'` and `/` as HTML/XML entity references. # - # assert "a&b-<>\"x\"/'".html_escape == "a&b-<>"x"/'" + # ~~~ + # assert "a&b-<>\"x\"/'".html_escape == "a&b-<>"x"/'" + # ~~~ # # SEE: fun html_escape: String @@ -940,19 +1024,23 @@ abstract class Text # Equality of text # Two pieces of text are equals if thez have the same characters in the same order. # - # assert "hello" == "hello" - # assert "hello" != "HELLO" - # assert "hello" == "hel"+"lo" + # ~~~ + # assert "hello" == "hello" + # assert "hello" != "HELLO" + # assert "hello" == "hel"+"lo" + # ~~~ # # Things that are not Text are not equal. # - # assert "9" != '9' - # assert "9" != ['9'] - # assert "9" != 9 + # ~~~ + # assert "9" != '9' + # assert "9" != ['9'] + # assert "9" != 9 # - # assert "9".chars.first == '9' # equality of Char - # assert "9".chars == ['9'] # equality of Sequence - # assert "9".to_i == 9 # equality of Int + # assert "9".chars.first == '9' # equality of Char + # assert "9".chars == ['9'] # equality of Sequence + # assert "9".to_i == 9 # equality of Int + # ~~~ redef fun ==(o) do if o == null then return false @@ -964,8 +1052,10 @@ abstract class Text # Lexicographical comparaison # - # assert "abc" < "xy" - # assert "ABC" < "abc" + # ~~~ + # assert "abc" < "xy" + # assert "ABC" < "abc" + # ~~~ redef fun <(other) do var self_chars = self.chars.iterator @@ -987,7 +1077,9 @@ abstract class Text # Escape string used in labels for graphviz # - # assert ">><<".escape_to_dot == "\\>\\>\\<\\<" + # ~~~ + # assert ">><<".escape_to_dot == "\\>\\>\\<\\<" + # ~~~ fun escape_to_dot: String do return escape_more_to_c("|\{\}<>") @@ -1016,8 +1108,10 @@ abstract class Text # The character `%` followed by something other than a number are left as is. # To represent a `%` followed by a number, double the `%`, as in `%%7`. # - # assert "This %0 is a %1.".format("String", "formatted String") == "This String is a formatted String." - # assert "Do not escape % nor %%1".format("unused") == "Do not escape % nor %1" + # ~~~ + # assert "This %0 is a %1.".format("String", "formatted String") == "This String is a formatted String." + # assert "Do not escape % nor %%1".format("unused") == "Do not escape % nor %1" + # ~~~ fun format(args: Object...): String do var s = new Array[Text] var curr_st = 0 @@ -1123,10 +1217,11 @@ abstract class Text # # REQUIRE: `n` must be large enough to contain `len` bytes # - # var ns = new CString(8) - # "Text is String".copy_to_native(ns, 8, 2, 0) - # assert ns.to_s_with_length(8) == "xt is St" - # + # ~~~ + # var ns = new CString(8) + # "Text is String".copy_to_native(ns, 8, 2, 0) + # assert ns.to_s_with_length(8) == "xt is St" + # ~~~ fun copy_to_native(dest: CString, n, src_offset, dest_offset: Int) do var mypos = src_offset var itspos = dest_offset @@ -1141,7 +1236,7 @@ abstract class Text # Packs the content of a string in packs of `ln` chars. # This variant ensures that only the last element might be smaller than `ln` # - # ~~~nit + # ~~~ # var s = "abcdefghijklmnopqrstuvwxyz" # assert s.pack_l(4) == ["abcd","efgh","ijkl","mnop","qrst","uvwx","yz"] # ~~~ @@ -1158,7 +1253,7 @@ abstract class Text # Packs the content of a string in packs of `ln` chars. # This variant ensures that only the first element might be smaller than `ln` # - # ~~~nit + # ~~~ # var s = "abcdefghijklmnopqrstuvwxyz" # assert s.pack_r(4) == ["ab","cdef","ghij","klmn","opqr","stuv","wxyz"] # ~~~ @@ -1174,83 +1269,107 @@ abstract class Text # Concatenates self `i` times # - #~~~nit - # assert "abc" * 4 == "abcabcabcabc" - # assert "abc" * 1 == "abc" - # assert "abc" * 0 == "" - # var b = new Buffer - # b.append("天地") - # b = b * 4 - # assert b == "天地天地天地天地" - #~~~ + # ~~~ + # assert "abc" * 4 == "abcabcabcabc" + # assert "abc" * 1 == "abc" + # assert "abc" * 0 == "" + # var b = new Buffer + # b.append("天地") + # b = b * 4 + # assert b == "天地天地天地天地" + # ~~~ fun *(i: Int): SELFTYPE is abstract # Insert `s` at `pos`. # - #~~~nit - # assert "helloworld".insert_at(" ", 5) == "hello world" - # var b = new Buffer - # b.append("Hello世界") - # b = b.insert_at(" beautiful ", 5) - # assert b == "Hello beautiful 世界" - #~~~ + # ~~~ + # assert "helloworld".insert_at(" ", 5) == "hello world" + # var b = new Buffer + # b.append("Hello世界") + # b = b.insert_at(" beautiful ", 5) + # assert b == "Hello beautiful 世界" + # ~~~ fun insert_at(s: String, pos: Int): SELFTYPE is abstract # Returns a reversed version of self # - # assert "hello".reversed == "olleh" - # assert "bob".reversed == "bob" - # assert "".reversed == "" + # ~~~ + # assert "hello".reversed == "olleh" + # assert "bob".reversed == "bob" + # assert "".reversed == "" + # ~~~ fun reversed: SELFTYPE is abstract # A upper case version of `self` # - # assert "Hello World!".to_upper == "HELLO WORLD!" + # ~~~ + # assert "Hello World!".to_upper == "HELLO WORLD!" + # ~~~ fun to_upper: SELFTYPE is abstract # A lower case version of `self` # - # assert "Hello World!".to_lower == "hello world!" + # ~~~ + # assert "Hello World!".to_lower == "hello world!" + # ~~~ fun to_lower : SELFTYPE is abstract # Takes a camel case `self` and converts it to snake case # - # assert "randomMethodId".to_snake_case == "random_method_id" + # ~~~ + # assert "randomMethodId".to_snake_case == "random_method_id" + # ~~~ # # The rules are the following: # # An uppercase is always converted to a lowercase # - # assert "HELLO_WORLD".to_snake_case == "hello_world" + # ~~~ + # assert "HELLO_WORLD".to_snake_case == "hello_world" + # ~~~ # # An uppercase that follows a lowercase is prefixed with an underscore # - # assert "HelloTheWORLD".to_snake_case == "hello_the_world" + # ~~~ + # assert "HelloTheWORLD".to_snake_case == "hello_the_world" + # ~~~ # # An uppercase that follows an uppercase and is followed by a lowercase, is prefixed with an underscore # - # assert "HelloTHEWorld".to_snake_case == "hello_the_world" + # ~~~ + # assert "HelloTHEWorld".to_snake_case == "hello_the_world" + # ~~~ # # All other characters are kept as is; `self` does not need to be a proper CamelCased string. # - # assert "=-_H3ll0Th3W0rld_-=".to_snake_case == "=-_h3ll0th3w0rld_-=" + # ~~~ + # assert "=-_H3ll0Th3W0rld_-=".to_snake_case == "=-_h3ll0th3w0rld_-=" + # ~~~ fun to_snake_case: SELFTYPE is abstract # Takes a snake case `self` and converts it to camel case # - # assert "random_method_id".to_camel_case == "randomMethodId" + # ~~~ + # assert "random_method_id".to_camel_case == "randomMethodId" + # ~~~ # # If the identifier is prefixed by an underscore, the underscore is ignored # - # assert "_private_field".to_camel_case == "_privateField" + # ~~~ + # assert "_private_field".to_camel_case == "_privateField" + # ~~~ # # If `self` is upper, it is returned unchanged # - # assert "RANDOM_ID".to_camel_case == "RANDOM_ID" + # ~~~ + # assert "RANDOM_ID".to_camel_case == "RANDOM_ID" + # ~~~ # # If there are several consecutive underscores, they are considered as a single one # - # assert "random__method_id".to_camel_case == "randomMethodId" + # ~~~ + # assert "random__method_id".to_camel_case == "randomMethodId" + # ~~~ fun to_camel_case: SELFTYPE is abstract # Returns a capitalized `self` @@ -1262,10 +1381,12 @@ abstract class Text # # SEE : `Char::is_letter` for the definition of letter. # - # assert "jAVASCRIPT".capitalized == "Javascript" - # assert "i am root".capitalized == "I Am Root" - # assert "ab_c -ab0c ab\nc".capitalized == "Ab_C -Ab0C Ab\nC" - # assert "preserve my ACRONYMS".capitalized(keep_upper=true) == "Preserve My ACRONYMS" + # ~~~ + # assert "jAVASCRIPT".capitalized == "Javascript" + # assert "i am root".capitalized == "I Am Root" + # assert "ab_c -ab0c ab\nc".capitalized == "Ab_C -Ab0C Ab\nC" + # assert "preserve my ACRONYMS".capitalized(keep_upper=true) == "Preserve My ACRONYMS" + # ~~~ fun capitalized(keep_upper: nullable Bool): SELFTYPE do if length == 0 then return self @@ -1341,7 +1462,7 @@ end # Abstract class for the SequenceRead compatible # views on the bytes of any Text private abstract class StringByteView - super SequenceRead[Byte] + super SequenceRead[Int] type SELFTYPE: Text @@ -1360,7 +1481,9 @@ end # # String objects may be created using literals. # -# assert "Hello World!" isa String +# ~~~ +# assert "Hello World!" isa String +# ~~~ abstract class String super Text @@ -1419,18 +1542,16 @@ abstract class Buffer protected var written = false # Modifies the char contained at pos `index` - # - # DEPRECATED : Use self.chars.[]= instead fun []=(index: Int, item: Char) is abstract redef fun to_buffer do return clone - #~~~nit - # var b = new Buffer - # b.append("Buffer!") - # var c = b.clone - # assert b == c - #~~~ + # ~~~ + # var b = new Buffer + # b.append("Buffer!") + # var c = b.clone + # assert b == c + # ~~~ redef fun clone do var cln = new Buffer.with_cap(byte_length) cln.append self @@ -1438,17 +1559,17 @@ abstract class Buffer end # Adds a char `c` at the end of self - # - # DEPRECATED : Use self.chars.add instead fun add(c: Char) is abstract # Clears the buffer # - # var b = new Buffer - # b.append "hello" - # assert not b.is_empty - # b.clear - # assert b.is_empty + # ~~~ + # var b = new Buffer + # b.append "hello" + # assert not b.is_empty + # b.clear + # assert b.is_empty + # ~~~ fun clear is abstract # Enlarges the subsequent array containing the chars of self @@ -1456,42 +1577,52 @@ abstract class Buffer # Adds the content of text `s` at the end of self # - # var b = new Buffer - # b.append "hello" - # b.append "world" - # assert b == "helloworld" + # ~~~ + # var b = new Buffer + # b.append "hello" + # b.append "world" + # assert b == "helloworld" + # ~~~ fun append(s: Text) is abstract # `self` is appended in such a way that `self` is repeated `r` times # - # var b = new Buffer - # b.append "hello" - # b.times 3 - # assert b == "hellohellohello" + # ~~~ + # var b = new Buffer + # b.append "hello" + # b.times 3 + # assert b == "hellohellohello" + # ~~~ fun times(r: Int) is abstract # Reverses itself in-place # - # var b = new Buffer - # b.append("hello") - # b.reverse - # assert b == "olleh" + # ~~~ + # var b = new Buffer + # b.append("hello") + # b.reverse + # assert b == "olleh" + # ~~~ fun reverse is abstract # Changes each lower-case char in `self` by its upper-case variant # - # var b = new Buffer - # b.append("Hello World!") - # b.upper - # assert b == "HELLO WORLD!" + # ~~~ + # var b = new Buffer + # b.append("Hello World!") + # b.upper + # assert b == "HELLO WORLD!" + # ~~~ fun upper is abstract # Changes each upper-case char in `self` by its lower-case variant # - # var b = new Buffer - # b.append("Hello World!") - # b.lower - # assert b == "hello world!" + # ~~~ + # var b = new Buffer + # b.append("Hello World!") + # b.lower + # assert b == "hello world!" + # ~~~ fun lower is abstract # Capitalizes each word in `self` @@ -1508,23 +1639,25 @@ abstract class Buffer # # SEE: `Char::is_letter` for the definition of a letter. # - # var b = new FlatBuffer.from("jAVAsCriPt") - # b.capitalize - # assert b == "Javascript" - # b = new FlatBuffer.from("i am root") - # b.capitalize - # assert b == "I Am Root" - # b = new FlatBuffer.from("ab_c -ab0c ab\nc") - # b.capitalize - # assert b == "Ab_C -Ab0C Ab\nC" - # - # b = new FlatBuffer.from("12345") - # b.capitalize(src="foo") - # assert b == "Foo45" - # - # b = new FlatBuffer.from("preserve my ACRONYMS") - # b.capitalize(keep_upper=true) - # assert b == "Preserve My ACRONYMS" + # ~~~ + # var b = new FlatBuffer.from("jAVAsCriPt") + # b.capitalize + # assert b == "Javascript" + # b = new FlatBuffer.from("i am root") + # b.capitalize + # assert b == "I Am Root" + # b = new FlatBuffer.from("ab_c -ab0c ab\nc") + # b.capitalize + # assert b == "Ab_C -Ab0C Ab\nC" + # + # b = new FlatBuffer.from("12345") + # b.capitalize(src="foo") + # assert b == "Foo45" + # + # b = new FlatBuffer.from("preserve my ACRONYMS") + # b.capitalize(keep_upper=true) + # assert b == "Preserve My ACRONYMS" + # ~~~ fun capitalize(keep_upper: nullable Bool, src: nullable Text) do src = src or else self var length = src.length @@ -1555,16 +1688,16 @@ abstract class Buffer # Appends `length` chars from `s` starting at index `from` # - # ~~~nit - # var b = new Buffer - # b.append_substring("abcde", 1, 2) - # assert b == "bc" - # b.append_substring("vwxyz", 2, 3) - # assert b == "bcxyz" - # b.append_substring("ABCDE", 4, 300) - # assert b == "bcxyzE" - # b.append_substring("VWXYZ", 400, 1) - # assert b == "bcxyzE" + # ~~~ + # var b = new Buffer + # b.append_substring("abcde", 1, 2) + # assert b == "bc" + # b.append_substring("vwxyz", 2, 3) + # assert b == "bcxyz" + # b.append_substring("ABCDE", 4, 300) + # assert b == "bcxyzE" + # b.append_substring("VWXYZ", 400, 1) + # assert b == "bcxyzE" # ~~~ fun append_substring(s: Text, from, length: Int) do if from < 0 then @@ -1602,36 +1735,36 @@ abstract class Buffer # Inserts `s` at position `pos` # - #~~~nit - # var b = new Buffer - # b.append "美しい世界" - # b.insert(" nit ", 3) - # assert b == "美しい nit 世界" - #~~~ + # ~~~ + # var b = new Buffer + # b.append "美しい世界" + # b.insert(" nit ", 3) + # assert b == "美しい nit 世界" + # ~~~ fun insert(s: Text, pos: Int) is abstract # Inserts `c` at position `pos` # - #~~~nit - # var b = new Buffer - # b.append "美しい世界" - # b.insert_char(' ', 3) - # assert b == "美しい 世界" - #~~~ + # ~~~ + # var b = new Buffer + # b.append "美しい世界" + # b.insert_char(' ', 3) + # assert b == "美しい 世界" + # ~~~ fun insert_char(c: Char, pos: Int) is abstract # Removes a substring from `self` at position `pos` # # NOTE: `length` defaults to 1, expressed in chars # - #~~~nit - # var b = new Buffer - # b.append("美しい 世界") - # b.remove_at(3) - # assert b == "美しい世界" - # b.remove_at(1, 2) - # assert b == "美世界" - #~~~ + # ~~~ + # var b = new Buffer + # b.append("美しい 世界") + # b.remove_at(3) + # assert b == "美しい世界" + # b.remove_at(1, 2) + # assert b == "美世界" + # ~~~ fun remove_at(pos: Int, length: nullable Int) is abstract redef fun reversed do @@ -1758,7 +1891,9 @@ redef class Object # The class name of the object. # - # assert 5.class_name == "Int" + # ~~~ + # assert 5.class_name == "Int" + # ~~~ fun class_name: String do return native_class_name.to_s # Developer readable representation of `self`. @@ -1777,8 +1912,10 @@ redef class Object end redef class Bool - # assert true.to_s == "true" - # assert false.to_s == "false" + # ~~~ + # assert true.to_s == "true" + # assert false.to_s == "false" + # ~~~ redef fun to_s do if self then @@ -1802,12 +1939,14 @@ redef class Byte # Displayable byte in its hexadecimal form (0x..) # - # assert 1.to_b.to_s == "0x01" - # assert (-123).to_b.to_s == "0x85" + # ~~~ + # assert 1.to_b.to_s == "0x01" + # assert (-123).to_b.to_s == "0x85" + # ~~~ redef fun to_s do var nslen = byte_to_s_len var ns = new CString(nslen + 1) - ns[nslen] = 0u8 + ns[nslen] = 0 native_byte_to_s(ns, nslen + 1) return ns.to_s_unsafe(nslen, copy=false, clean=false) end @@ -1876,16 +2015,20 @@ redef class Int # return displayable int in hexadecimal # - # assert 1.to_hex == "1" - # assert (-255).to_hex == "-ff" + # ~~~ + # assert 1.to_hex == "1" + # assert (-255).to_hex == "-ff" + # ~~~ fun to_hex: String do return to_base(16) end redef class Float # Pretty representation of `self`, with decimals as needed from 1 to a maximum of 3 # - # assert 12.34.to_s == "12.34" - # assert (-0120.030).to_s == "-120.03" + # ~~~ + # assert 12.34.to_s == "12.34" + # assert (-0120.030).to_s == "-120.03" + # ~~~ # # see `to_precision` for a custom precision. redef fun to_s do @@ -1908,12 +2051,14 @@ redef class Float # `String` representation of `self` with the given number of `decimals` # - # assert 12.345.to_precision(0) == "12" - # assert 12.345.to_precision(3) == "12.345" - # assert (-12.345).to_precision(3) == "-12.345" - # assert (-0.123).to_precision(3) == "-0.123" - # assert 0.999.to_precision(2) == "1.00" - # assert 0.999.to_precision(4) == "0.9990" + # ~~~ + # assert 12.345.to_precision(0) == "12" + # assert 12.345.to_precision(3) == "12.345" + # assert (-12.345).to_precision(3) == "-12.345" + # assert (-0.123).to_precision(3) == "-0.123" + # assert 0.999.to_precision(2) == "1.00" + # assert 0.999.to_precision(4) == "0.9990" + # ~~~ fun to_precision(decimals: Int): String do if is_nan then return "nan" @@ -1948,9 +2093,11 @@ redef class Char # Returns a sequence with the UTF-8 bytes of `self` # - # assert 'a'.bytes == [0x61u8] - # assert 'ま'.bytes == [0xE3u8, 0x81u8, 0xBEu8] - fun bytes: SequenceRead[Byte] do return to_s.bytes + # ~~~ + # assert 'a'.bytes == [0x61] + # assert 'ま'.bytes == [0xE3, 0x81, 0xBE] + # ~~~ + fun bytes: SequenceRead[Int] do return to_s.bytes # Is `self` an UTF-16 surrogate pair ? fun is_surrogate: Bool do @@ -1981,7 +2128,9 @@ redef class Char return 1 end - # assert 'x'.to_s == "x" + # ~~~ + # assert 'x'.to_s == "x" + # ~~~ redef fun to_s do var ln = u8char_len var ns = new CString(ln + 1) @@ -1994,10 +2143,12 @@ redef class Char # i.e. Represents `self`.`code_point` using UTF-16 codets escaped # with a `\u` # - # assert 'A'.escape_to_utf16 == "\\u0041" - # assert 'è'.escape_to_utf16 == "\\u00e8" - # assert 'あ'.escape_to_utf16 == "\\u3042" - # assert '𐏓'.escape_to_utf16 == "\\ud800\\udfd3" + # ~~~ + # assert 'A'.escape_to_utf16 == "\\u0041" + # assert 'è'.escape_to_utf16 == "\\u00e8" + # assert 'あ'.escape_to_utf16 == "\\u3042" + # assert '𐏓'.escape_to_utf16 == "\\ud800\\udfd3" + # ~~~ fun escape_to_utf16: String do var cp = code_point var buf: Buffer @@ -2055,10 +2206,12 @@ redef class Char # Returns true if the char is a numerical digit # - # assert '0'.is_numeric - # assert '9'.is_numeric - # assert not 'a'.is_numeric - # assert not '?'.is_numeric + # ~~~ + # assert '0'.is_numeric + # assert '9'.is_numeric + # assert not 'a'.is_numeric + # assert not '?'.is_numeric + # ~~~ # # FIXME: Works on ASCII-range only fun is_numeric: Bool @@ -2068,10 +2221,12 @@ redef class Char # Returns true if the char is an alpha digit # - # assert 'a'.is_alpha - # assert 'Z'.is_alpha - # assert not '0'.is_alpha - # assert not '?'.is_alpha + # ~~~ + # assert 'a'.is_alpha + # assert 'Z'.is_alpha + # assert not '0'.is_alpha + # assert not '?'.is_alpha + # ~~~ # # FIXME: Works on ASCII-range only fun is_alpha: Bool @@ -2081,21 +2236,25 @@ redef class Char # Is `self` an hexadecimal digit ? # - # assert 'A'.is_hexdigit - # assert not 'G'.is_hexdigit - # assert 'a'.is_hexdigit - # assert not 'g'.is_hexdigit - # assert '5'.is_hexdigit + # ~~~ + # assert 'A'.is_hexdigit + # assert not 'G'.is_hexdigit + # assert 'a'.is_hexdigit + # assert not 'g'.is_hexdigit + # assert '5'.is_hexdigit + # ~~~ fun is_hexdigit: Bool do return (self >= '0' and self <= '9') or (self >= 'A' and self <= 'F') or (self >= 'a' and self <= 'f') # Returns true if the char is an alpha or a numeric digit # - # assert 'a'.is_alphanumeric - # assert 'Z'.is_alphanumeric - # assert '0'.is_alphanumeric - # assert '9'.is_alphanumeric - # assert not '?'.is_alphanumeric + # ~~~ + # assert 'a'.is_alphanumeric + # assert 'Z'.is_alphanumeric + # assert '0'.is_alphanumeric + # assert '9'.is_alphanumeric + # assert not '?'.is_alphanumeric + # ~~~ # # FIXME: Works on ASCII-range only fun is_alphanumeric: Bool @@ -2152,13 +2311,17 @@ redef class Collection[E] # # Only concatenate if `separator == null`. # - # assert [1, 2, 3].join(":") == "1:2:3" - # assert [1..3].join(":") == "1:2:3" - # assert [1..3].join == "123" + # ~~~ + # assert [1, 2, 3].join(":") == "1:2:3" + # assert [1..3].join(":") == "1:2:3" + # assert [1..3].join == "123" + # ~~~ # # if `last_separator` is given, then it is used to separate the last element. # - # assert [1, 2, 3, 4].join(", ", " and ") == "1, 2, 3 and 4" + # ~~~ + # assert [1, 2, 3, 4].join(", ", " and ") == "1, 2, 3 and 4" + # ~~~ fun join(separator: nullable Text, last_separator: nullable Text): String do if is_empty then return "" @@ -2193,10 +2356,12 @@ redef class Map[K,V] # Key and value are separated by `couple_sep`. # Couples are separated by `sep`. # - # var m = new HashMap[Int, String] - # m[1] = "one" - # m[10] = "ten" - # assert m.join("; ", "=") == "1=one; 10=ten" + # ~~~ + # var m = new HashMap[Int, String] + # m[1] = "one" + # m[10] = "ten" + # assert m.join("; ", "=") == "1=one; 10=ten" + # ~~~ fun join(sep, couple_sep: String): String is abstract end @@ -2240,9 +2405,11 @@ end # # The comparaison call `to_s` on object and use the result to order things. # -# var a = [1, 2, 3, 10, 20] -# (new CachedAlphaComparator).sort(a) -# assert a == [1, 10, 2, 20, 3] +# ~~~ +# var a = [1, 2, 3, 10, 20] +# (new CachedAlphaComparator).sort(a) +# assert a == [1, 10, 2, 20, 3] +# ~~~ # # Internally the result of `to_s` is cached in a HashMap to counter # uneficient implementation of `to_s`. @@ -2282,9 +2449,11 @@ end # Note: the result of `to_s` is not cached, thus can be invoked a lot # on a single instace. See `CachedAlphaComparator` as an alternative. # -# var a = [1, 2, 3, 10, 20] -# alpha_comparator.sort(a) -# assert a == [1, 10, 2, 20, 3] +# ~~~ +# var a = [1, 2, 3, 10, 20] +# alpha_comparator.sort(a) +# assert a == [1, 10, 2, 20, 3] +# ~~~ fun alpha_comparator: Comparator do return once new AlphaComparator # The arguments of the program as given by the OS diff --git a/lib/core/text/fixed_ints_text.nit b/lib/core/text/fixed_ints_text.nit index 88a21a4..c738f91 100644 --- a/lib/core/text/fixed_ints_text.nit +++ b/lib/core/text/fixed_ints_text.nit @@ -40,7 +40,7 @@ redef class Int8 redef fun to_s do var nslen = to_s_len var ns = new CString(nslen + 1) - ns[nslen] = 0u8 + ns[nslen] = 0 native_to_s(ns, nslen + 1) return ns.to_s_unsafe(nslen, copy=false) end @@ -63,7 +63,7 @@ redef class Int16 redef fun to_s do var nslen = to_s_len var ns = new CString(nslen + 1) - ns[nslen] = 0u8 + ns[nslen] = 0 native_to_s(ns, nslen + 1) return ns.to_s_unsafe(nslen, copy=false) end @@ -87,7 +87,7 @@ redef class UInt16 redef fun to_s do var nslen = to_s_len var ns = new CString(nslen + 1) - ns[nslen] = 0u8 + ns[nslen] = 0 native_to_s(ns, nslen + 1) return ns.to_s_unsafe(nslen, copy=false) end @@ -111,7 +111,7 @@ redef class Int32 redef fun to_s do var nslen = to_s_len var ns = new CString(nslen + 1) - ns[nslen] = 0u8 + ns[nslen] = 0 native_to_s(ns, nslen + 1) return ns.to_s_unsafe(nslen, copy=false) end @@ -135,7 +135,7 @@ redef class UInt32 redef fun to_s do var nslen = to_s_len var ns = new CString(nslen + 1) - ns[nslen] = 0u8 + ns[nslen] = 0 native_to_s(ns, nslen + 1) return ns.to_s_unsafe(nslen, copy=false) end diff --git a/lib/core/text/flat.nit b/lib/core/text/flat.nit index b728e42..cc60978 100644 --- a/lib/core/text/flat.nit +++ b/lib/core/text/flat.nit @@ -55,7 +55,7 @@ redef class FlatText var its = _items if dpos == 1 then - if its[b] & 0x80u8 == 0x00u8 then + if its[b] & 0x80 == 0x00 then b += 1 else b += its.length_of_char_at(b) @@ -113,17 +113,17 @@ redef class FlatText var endlen = 0 while pos <= max do var c = its[pos] - if c == b'<' then + if c == u'<' then endlen += 3 - else if c == b'>' then + else if c == u'>' then endlen += 3 - else if c == b'&' then + else if c == u'&' then endlen += 4 - else if c == b'"' then + else if c == u'"' then endlen += 4 - else if c == b'\'' then + else if c == u'\'' then endlen += 4 - else if c == 0x2Fu8 then + else if c == 0x2F then endlen += 4 end pos += 1 @@ -146,45 +146,45 @@ redef class FlatText # Special codes: # Some HTML characters are used as meta-data, they need # to be replaced by an HTML-Escaped equivalent - if c == b'<' then - nits[outpos] = b'&' - nits[outpos + 1] = b'l' - nits[outpos + 2] = b't' - nits[outpos + 3] = b';' + if c == u'<' then + nits[outpos] = u'&' + nits[outpos + 1] = u'l' + nits[outpos + 2] = u't' + nits[outpos + 3] = u';' outpos += 4 - else if c == b'>' then - nits[outpos] = b'&' - nits[outpos + 1] = b'g' - nits[outpos + 2] = b't' - nits[outpos + 3] = b';' + else if c == u'>' then + nits[outpos] = u'&' + nits[outpos + 1] = u'g' + nits[outpos + 2] = u't' + nits[outpos + 3] = u';' outpos += 4 - else if c == b'&' then - nits[outpos] = b'&' - nits[outpos + 1] = b'a' - nits[outpos + 2] = b'm' - nits[outpos + 3] = b'p' - nits[outpos + 4] = b';' + else if c == u'&' then + nits[outpos] = u'&' + nits[outpos + 1] = u'a' + nits[outpos + 2] = u'm' + nits[outpos + 3] = u'p' + nits[outpos + 4] = u';' outpos += 5 - else if c == b'"' then - nits[outpos] = b'&' - nits[outpos + 1] = b'#' - nits[outpos + 2] = b'3' - nits[outpos + 3] = b'4' - nits[outpos + 4] = b';' + else if c == u'"' then + nits[outpos] = u'&' + nits[outpos + 1] = u'#' + nits[outpos + 2] = u'3' + nits[outpos + 3] = u'4' + nits[outpos + 4] = u';' outpos += 5 - else if c == b'\'' then - nits[outpos] = b'&' - nits[outpos + 1] = b'#' - nits[outpos + 2] = b'3' - nits[outpos + 3] = b'9' - nits[outpos + 4] = b';' + else if c == u'\'' then + nits[outpos] = u'&' + nits[outpos + 1] = u'#' + nits[outpos + 2] = u'3' + nits[outpos + 3] = u'9' + nits[outpos + 4] = u';' outpos += 5 - else if c == 0x2Fu8 then - nits[outpos] = b'&' - nits[outpos + 1] = b'#' - nits[outpos + 2] = b'4' - nits[outpos + 3] = b'7' - nits[outpos + 4] = b';' + else if c == u'/' then + nits[outpos] = u'&' + nits[outpos + 1] = u'#' + nits[outpos + 2] = u'4' + nits[outpos + 3] = u'7' + nits[outpos + 4] = u';' outpos += 5 else nits[outpos] = c @@ -208,33 +208,33 @@ redef class FlatText var req_esc = 0 while pos <= max do var c = its[pos] - if c == b'\n' then + if c == u'\n' then req_esc += 1 - else if c == b'\t' then + else if c == u'\t' then req_esc += 1 - else if c == b'"' then + else if c == u'"' then req_esc += 1 - else if c == b'\'' then + else if c == u'\'' then req_esc += 1 - else if c == b'\\' then + else if c == u'\\' then req_esc += 1 - else if c == 0x3Fu8 then + else if c == u'?' then var j = pos + 1 if j < length then var next = its[j] # We ignore `??'` because it will be escaped as `??\'`. if - next == 0x21u8 or - next == 0x28u8 or - next == 0x29u8 or - next == 0x2Du8 or - next == 0x2Fu8 or - next == 0x3Cu8 or - next == 0x3Du8 or - next == 0x3Eu8 + next == 0x21 or + next == 0x28 or + next == 0x29 or + next == 0x2D or + next == 0x2F or + next == 0x3C or + next == 0x3D or + next == 0x3E then req_esc += 1 end - else if c < 32u8 then + else if c < 32 then req_esc += 3 end pos += 1 @@ -269,52 +269,52 @@ redef class FlatText # * 0x22 => \" # * 0x27 => \' # * 0x5C => \\ - if c == b'\t' then - nns[opos] = b'\\' - nns[opos + 1] = b't' + if c == u'\t' then + nns[opos] = u'\\' + nns[opos + 1] = u't' opos += 2 - else if c == b'\n' then - nns[opos] = b'\\' - nns[opos + 1] = b'n' + else if c == u'\n' then + nns[opos] = u'\\' + nns[opos + 1] = u'n' opos += 2 - else if c == b'"' then - nns[opos] = b'\\' - nns[opos + 1] = b'"' + else if c == u'"' then + nns[opos] = u'\\' + nns[opos + 1] = u'"' opos += 2 - else if c == b'\'' then - nns[opos] = b'\\' - nns[opos + 1] = b'\'' + else if c == u'\'' then + nns[opos] = u'\\' + nns[opos + 1] = u'\'' opos += 2 - else if c == b'\\' then - nns[opos] = b'\\' - nns[opos + 1] = b'\\' + else if c == u'\\' then + nns[opos] = u'\\' + nns[opos + 1] = u'\\' opos += 2 - else if c == 0x3Fu8 then + else if c == u'?' then var j = pos + 1 if j < length then var next = its[j] # We ignore `??'` because it will be escaped as `??\'`. if - next == 0x21u8 or - next == 0x28u8 or - next == 0x29u8 or - next == 0x2Du8 or - next == 0x2Fu8 or - next == 0x3Cu8 or - next == 0x3Du8 or - next == 0x3Eu8 + next == 0x21 or + next == 0x28 or + next == 0x29 or + next == 0x2D or + next == 0x2F or + next == 0x3C or + next == 0x3D or + next == 0x3E then - nns[opos] = 0x5Cu8 + nns[opos] = 0x5C opos += 1 end end - nns[opos] = 0x3Fu8 + nns[opos] = 0x3F opos += 1 - else if c < 32u8 then - nns[opos] = b'\\' - nns[opos + 1] = b'0' - nns[opos + 2] = ((c & 0x38u8) >> 3) + b'0' - nns[opos + 3] = (c & 0x07u8) + b'0' + else if c < 32 then + nns[opos] = u'\\' + nns[opos + 1] = u'0' + nns[opos + 2] = ((c & 0x38) >> 3) + u'0' + nns[opos + 3] = (c & 0x07) + u'0' opos += 4 else nns[opos] = c @@ -339,7 +339,7 @@ redef class FlatText if dpos == 1 and index < len - 1 then var its = _items var c = its[b] - if c & 0x80u8 == 0x00u8 then + if c & 0x80 == 0x00 then # We want the next, and current is easy. # So next is easy to find! b += 1 @@ -351,20 +351,20 @@ redef class FlatText else if dpos == -1 and index > 1 then var its = _items var c = its[b-1] - if c & 0x80u8 == 0x00u8 then + if c & 0x80 == 0x00 then # We want the previous, and it is easy. b -= 1 dpos = 0 _position = index _bytepos = b - return c.ascii + return c.code_point end end if dpos == 0 then # We know what we want (+0 or +1) just get it now! var its = _items var c = its[b] - if c & 0x80u8 == 0x00u8 then return c.ascii + if c & 0x80 == 0x00 then return c.code_point return items.char_at(b) end @@ -379,7 +379,7 @@ redef class FlatText var i = char_to_byte_index(index) var items = _items var b = items[i] - if b & 0x80u8 == 0x00u8 then return b.ascii + if b & 0x80 == 0x00 then return b.code_point return items.char_at(i) end @@ -395,7 +395,7 @@ redef class FlatText var max = pos + ln for i in [pos .. max[ do res <<= 4 - res += its[i].ascii.from_hex + res += its[i].code_point.from_hex end return res end @@ -421,7 +421,7 @@ abstract class FlatString var blen = _byte_length var new_items = new CString(blen + 1) _items.copy_to(new_items, blen, _first_byte, 0) - new_items[blen] = 0u8 + new_items[blen] = 0 return new_items end @@ -624,7 +624,7 @@ abstract class FlatString var its = _items var fb = _first_byte var ns = new CString(new_byte_length + 1) - ns[new_byte_length] = 0u8 + ns[new_byte_length] = 0 var offset = 0 while i > 0 do its.copy_to(ns, mybtlen, fb, offset) @@ -696,7 +696,7 @@ private class ASCIIFlatString redef fun [](idx) do assert idx < _byte_length and idx >= 0 - return _items[idx + _first_byte].ascii + return _items[idx + _first_byte].code_point end redef fun substring(from, count) do @@ -729,7 +729,7 @@ private class ASCIIFlatString return new ASCIIFlatString.full_data(_items, count, from + _first_byte, count) end - redef fun fetch_char_at(i) do return _items[i + _first_byte].ascii + redef fun fetch_char_at(i) do return _items[i + _first_byte].code_point end private class FlatStringCharReverseIterator @@ -784,7 +784,7 @@ private class FlatStringCharView end private class FlatStringByteReverseIterator - super IndexedIterator[Byte] + super IndexedIterator[Int] var target: FlatString @@ -810,7 +810,7 @@ private class FlatStringByteReverseIterator end private class FlatStringByteIterator - super IndexedIterator[Byte] + super IndexedIterator[Int] var target: FlatString @@ -1019,7 +1019,7 @@ class FlatBuffer do var bln = _byte_length var new_native = new CString(bln + 1) - new_native[bln] = 0u8 + new_native[bln] = 0 if _length > 0 then _items.copy_to(new_native, bln, 0, 0) return new_native end @@ -1163,7 +1163,7 @@ class FlatBuffer end private class FlatBufferByteReverseIterator - super IndexedIterator[Byte] + super IndexedIterator[Int] var target: FlatBuffer @@ -1197,7 +1197,7 @@ private class FlatBufferByteView end private class FlatBufferByteIterator - super IndexedIterator[Byte] + super IndexedIterator[Int] var target: FlatBuffer @@ -1331,7 +1331,7 @@ redef class CString if copy and (str == null or str.items == self) then var new_cstr = new CString(byte_length + 1) copy_to(new_cstr, byte_length, 0, 0) - new_cstr[byte_length] = 0u8 + new_cstr[byte_length] = 0 str = new FlatString.full(new_cstr, byte_length, 0, char_length) end @@ -1359,7 +1359,7 @@ redef class CString end if rem == 0 then break var b = self[pos] - if b & 0x80u8 == 0x00u8 then + if b & 0x80 == 0x00 then pos += 1 chr_ln += 1 rem -= 1 @@ -1368,13 +1368,13 @@ redef class CString var nxst = length_of_char_at(pos) var ok_st: Bool if nxst == 1 then - ok_st = b & 0x80u8 == 0u8 + ok_st = b & 0x80 == 0 else if nxst == 2 then - ok_st = b & 0xE0u8 == 0xC0u8 + ok_st = b & 0xE0 == 0xC0 else if nxst == 3 then - ok_st = b & 0xF0u8 == 0xE0u8 + ok_st = b & 0xF0 == 0xE0 else - ok_st = b & 0xF8u8 == 0xF0u8 + ok_st = b & 0xF8 == 0xF0 end if not ok_st then if replacements == null then replacements = new Array[Int] @@ -1425,9 +1425,9 @@ redef class CString var chkln = repl_pos - old_repl copy_to(ret, chkln, old_repl, off) off += chkln - ret[off] = 0xEFu8 - ret[off + 1] = 0xBFu8 - ret[off + 2] = 0xBDu8 + ret[off] = 0xEF + ret[off + 1] = 0xBF + ret[off + 2] = 0xBD old_repl = repl_pos + 1 off += 3 end @@ -1442,22 +1442,22 @@ redef class CString private fun set_char_at(pos: Int, c: Char) do var cp = c.code_point if cp < 128 then - self[pos] = cp.to_b + self[pos] = cp return end var ln = c.u8char_len if ln == 2 then - self[pos] = (0xC0 | ((cp & 0x7C0) >> 6)).to_b - self[pos + 1] = (0x80 | (cp & 0x3F)).to_b + self[pos] = 0xC0 | ((cp & 0x7C0) >> 6) + self[pos + 1] = 0x80 | (cp & 0x3F) else if ln == 3 then - self[pos] = (0xE0 | ((cp & 0xF000) >> 12)).to_b - self[pos + 1] = (0x80 | ((cp & 0xFC0) >> 6)).to_b - self[pos + 2] = (0x80 | (cp & 0x3F)).to_b + self[pos] = 0xE0 | ((cp & 0xF000) >> 12) + self[pos + 1] = 0x80 | ((cp & 0xFC0) >> 6) + self[pos + 2] = 0x80 | (cp & 0x3F) else if ln == 4 then - self[pos] = (0xF0 | ((cp & 0x1C0000) >> 18)).to_b - self[pos + 1] = (0x80 | ((cp & 0x3F000) >> 12)).to_b - self[pos + 2] = (0x80 | ((cp & 0xFC0) >> 6)).to_b - self[pos + 3] = (0x80 | (cp & 0x3F)).to_b + self[pos] = 0xF0 | ((cp & 0x1C0000) >> 18) + self[pos + 1] = 0x80 | ((cp & 0x3F000) >> 12) + self[pos + 2] = 0x80 | ((cp & 0xFC0) >> 6) + self[pos + 3] = 0x80 | (cp & 0x3F) end end end @@ -1474,7 +1474,7 @@ redef class Int var nslen = int_to_s_len var ns = new CString(nslen + 1) - ns[nslen] = 0u8 + ns[nslen] = 0 native_int_to_s(ns, nslen + 1) return new FlatString.full(ns, nslen, 0, nslen) end @@ -1507,7 +1507,7 @@ redef class Array[E] mypos += 1 end var ns = new CString(sl + 1) - ns[sl] = 0u8 + ns[sl] = 0 i = 0 var off = 0 while i < mypos do @@ -1544,7 +1544,7 @@ redef class NativeArray[E] mypos += 1 end var ns = new CString(sl + 1) - ns[sl] = 0u8 + ns[sl] = 0 i = 0 var off = 0 while i < mypos do diff --git a/lib/core/text/native.nit b/lib/core/text/native.nit index 74f5f3f..372ac5a 100644 --- a/lib/core/text/native.nit +++ b/lib/core/text/native.nit @@ -35,16 +35,16 @@ in "C" `{ #include `} -redef class Byte +redef class Int # Gives the length of the UTF-8 char starting with `self` fun u8len: Int do - if self & 0b1000_0000u8 == 0u8 then + if self & 0b1000_0000 == 0 then return 1 - else if self & 0b1110_0000u8 == 0b1100_0000u8 then + else if self & 0b1110_0000 == 0b1100_0000 then return 2 - else if self & 0b1111_0000u8 == 0b1110_0000u8 then + else if self & 0b1111_0000 == 0b1110_0000 then return 3 - else if self & 0b1111_1000u8 == 0b1111_0000u8 then + else if self & 0b1111_1000 == 0b1111_0000 then return 4 else return 1 @@ -54,16 +54,16 @@ redef class Byte # Is `self` a valid UTF-8 sequence start ? # # ~~~nit - # assert 0u8.is_valid_utf8_start - # assert 0xC0u8.is_valid_utf8_start - # assert 0xE0u8.is_valid_utf8_start - # assert 0xF0u8.is_valid_utf8_start + # assert 0.is_valid_utf8_start + # assert 0xC0.is_valid_utf8_start + # assert 0xE0.is_valid_utf8_start + # assert 0xF0.is_valid_utf8_start # ~~~ fun is_valid_utf8_start: Bool do - if self & 0x80u8 == 0u8 then return true - if self & 0b1110_0000u8 == 0b1100_0000u8 then return true - if self & 0b1111_0000u8 == 0b1110_0000u8 then return true - if self & 0b1111_1000u8 == 0b1111_0000u8 then return true + if self & 0x80 == 0 then return true + if self & 0b1110_0000 == 0b1100_0000 then return true + if self & 0b1111_0000 == 0b1110_0000 then return true + if self & 0b1111_1000 == 0b1111_0000 then return true return false end end @@ -104,10 +104,10 @@ extern class CString `{ char* `} fun fast_cstring(index: Int): CString is intern # Get char at `index`. - fun [](index: Int): Byte is intern + fun [](index: Int): Int is intern # Set char `item` at index. - fun []=(index: Int, item: Byte) is intern + fun []=(index: Int, item: Int) is intern # Copy `self` to `dest`. fun copy_to(dest: CString, length: Int, from: Int, to: Int) is intern @@ -120,7 +120,7 @@ extern class CString `{ char* `} fun cstring_length: Int do var l = 0 - while self[l] != 0u8 do l += 1 + while self[l] != 0 do l += 1 return l end @@ -146,7 +146,7 @@ extern class CString `{ char* `} # ~~~ fun char_at(pos: Int): Char do var c = self[pos] - if c & 0x80u8 == 0u8 then return c.ascii + if c & 0x80 == 0 then return c.code_point var b = fetch_4_hchars(pos) var ret = 0u32 if b & 0xC00000u32 != 0x800000u32 then return 0xFFFD.code_point @@ -179,13 +179,13 @@ extern class CString `{ char* `} # Gets the length of the character at position `pos` (1 if invalid sequence) fun length_of_char_at(pos: Int): Int do var c = self[pos] - if c & 0x80u8 == 0x00u8 then + if c & 0x80 == 0x00 then return 1 - else if c & 0xE0u8 == 0xC0u8 and self[pos + 1] & 0xC0u8 == 0x80u8 then + else if c & 0xE0 == 0xC0 and self[pos + 1] & 0xC0 == 0x80 then return 2 - else if c & 0xF0u8 == 0xE0u8 and self[pos + 1] & 0xC0u8 == 0x80u8 and self[pos + 2] & 0xC0u8 == 0x80u8 then + else if c & 0xF0 == 0xE0 and self[pos + 1] & 0xC0 == 0x80 and self[pos + 2] & 0xC0 == 0x80 then return 3 - else if c & 0xF8u8 == 0xF0u8 and self[pos + 1] & 0xC0u8 == 0x80u8 and self[pos + 2] & 0xC0u8 == 0x80u8 and self[pos + 3] & 0xC0u8 == 0x80u8 then + else if c & 0xF8 == 0xF0 and self[pos + 1] & 0xC0 == 0x80 and self[pos + 2] & 0xC0 == 0x80 and self[pos + 3] & 0xC0 == 0x80 then return 4 else return 1 @@ -265,13 +265,13 @@ extern class CString `{ char* `} # ~~~raw # assert "abc".items.find_beginning_of_char_at(2) == 2 # assert "か".items.find_beginning_of_char_at(1) == 0 - # assert [0x41u8, 233u8].to_s.items.find_beginning_of_char_at(1) == 1 + # assert [0x41, 233].to_s.items.find_beginning_of_char_at(1) == 1 # ~~~ fun find_beginning_of_char_at(pos: Int): Int do var endpos = pos var c = self[pos] - if c & 0x80u8 == 0x00u8 then return pos - while c & 0xC0u8 == 0x80u8 do + if c & 0x80 == 0x00 then return pos + while c & 0xC0 == 0x80 do pos -= 1 c = self[pos] end diff --git a/lib/core/text/ropes.nit b/lib/core/text/ropes.nit index ca846fd..ef0016c 100644 --- a/lib/core/text/ropes.nit +++ b/lib/core/text/ropes.nit @@ -91,7 +91,7 @@ private class Concat redef fun to_cstring do var len = _byte_length var ns = new CString(len + 1) - ns[len] = 0u8 + ns[len] = 0 var off = 0 for i in substrings do var ilen = i._byte_length @@ -331,7 +331,7 @@ end # A reverse iterator capable of working with `Rope` objects private class RopeByteReverseIterator - super IndexedIterator[Byte] + super IndexedIterator[Int] # Current CString var ns: CString is noautoinit @@ -372,7 +372,7 @@ end # Forward iterator on the bytes of a `Rope` private class RopeByteIterator - super IndexedIterator[Byte] + super IndexedIterator[Int] # Position in current `String` var pns: Int is noautoinit diff --git a/lib/crapto/xor.nit b/lib/crapto/xor.nit index 8745c1a..6402969 100644 --- a/lib/crapto/xor.nit +++ b/lib/crapto/xor.nit @@ -26,20 +26,20 @@ redef class SingleByteXorCipher # Accumulate best result var max = 0.0 - var best = 0.to_b + var best = 0 # Iterate on possible values for a byte var xor_b = new Bytes.with_capacity(1) for b in [0 .. 255] do # Need `Bytes` to pass to xor - xor_b[0] = b.to_b + xor_b[0] = b # Xor and evaluate result var xored = ciphertext.xorcipher(xor_b) var result = xored.to_s.english_scoring if result > max then max = result - best = b.to_b + best = b end end diff --git a/lib/crypto/basic_ciphers.nit b/lib/crypto/basic_ciphers.nit index e4a133c..7181928 100644 --- a/lib/crypto/basic_ciphers.nit +++ b/lib/crypto/basic_ciphers.nit @@ -154,6 +154,56 @@ redef class Text end return arr.to_s end + + # Vigenere encoder on ASCII letters. + # + # Only the letters in '[A-Za-z]' are encoded while keeping the case. + # + # assert "Hello, World!".vigenere("abc") == "Hfnlp, Yosnd!" + # + # REQUIRE `key` contains only lowercases '[a-z]' + fun vigenere(key: String): String + do + var res = new Buffer + res.enlarge(length) + var i = 0 + for c in self do + var k = key[i%key.length] + assert k >= 'a' and k <= 'z' + if c.is_letter then + var d = k.code_point - 'a'.code_point + c = c.rot(d) + i += 1 + end + res.add c + end + return res.to_s + end + + # Vigenere decoder on ASCII letters. + # + # Only the letters in '[A-Za-z]' are decoded while keeping the case. + # + # assert "Hfnlp, Yosnd!".uvigenere("abc") == "Hello, World!" + # + # REQUIRE `key` contains only lowercases '[a-z]' + fun uvigenere(key: String): String + do + var res = new Buffer + res.enlarge(length) + var i = 0 + for c in self do + var k = key[i%key.length] + assert k >= 'a' and k <= 'z' + if c.is_letter then + var d = k.code_point - 'a'.code_point + c = c.rot(-d) + i += 1 + end + res.add c + end + return res.to_s + end end redef class Bytes @@ -162,12 +212,12 @@ redef class Bytes # assert "this is a test".to_bytes.hamming_distance("wokka wokka!!!".bytes) == 37 # assert "this is a test".to_bytes.hamming_distance("this is a test".bytes) == 0 # - fun hamming_distance(other: SequenceRead[Byte]): Int do + fun hamming_distance(other: SequenceRead[Int]): Int do var diff = 0 for idx in self.length.times do var res_byte = self[idx] ^ other[idx] for bit in [0..8[ do - if res_byte & 1u8 == 1u8 then diff += 1 + if res_byte & 1 == 1 then diff += 1 res_byte = res_byte >> 1 end end diff --git a/lib/crypto/bytes.nit b/lib/crypto/bytes.nit new file mode 100644 index 0000000..287d782 --- /dev/null +++ b/lib/crypto/bytes.nit @@ -0,0 +1,33 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Mix of utilities and services related to bytes +module bytes + +redef class Bytes + # PKCS#7 padding. + # + # Extends `self` by appending the number of bytes of padding to the end of the block. + # + # assert "YELLOW SUBMARINE".to_bytes.pkcs7(20) == "YELLOW SUBMARINE\x04\x04\x04\x04".to_bytes + fun pkcs7(blocksize: Int): Bytes + do + var mod = length % blocksize + if mod == 0 then return self + var pad = blocksize - mod + var byte = pad + for i in [0..pad[ do add byte + return self + end +end diff --git a/lib/crypto/crypto.nit b/lib/crypto/crypto.nit index 4709403..97d7cee 100644 --- a/lib/crypto/crypto.nit +++ b/lib/crypto/crypto.nit @@ -17,3 +17,4 @@ module crypto import basic_ciphers import xor_ciphers +import bytes diff --git a/lib/crypto/xor_ciphers.nit b/lib/crypto/xor_ciphers.nit index 18de9fb..aaa18d1 100644 --- a/lib/crypto/xor_ciphers.nit +++ b/lib/crypto/xor_ciphers.nit @@ -69,7 +69,7 @@ class SingleByteXorCipher super Cipher # Cryptographic key used in encryption and decryption. - var key: Byte = 0.to_b + var key: Int = 0 redef fun encrypt do var key_bytes = new Bytes.with_capacity(1) diff --git a/lib/gamnit/textures.nit b/lib/gamnit/textures.nit index 4383c2b..4987be2 100644 --- a/lib/gamnit/textures.nit +++ b/lib/gamnit/textures.nit @@ -161,10 +161,10 @@ class CustomTexture # Simple conversion from [0.0..1.0] to [0..255] var bytes = [for c in color do (c*255.0).round.to_i.clamp(0, 255).to_bytes.last] - while bytes.length < 4 do bytes.add 255u8 + while bytes.length < 4 do bytes.add 255 var offset = 4*(x + y*width.to_i) - for i in [0..4[ do cpixels[offset+i] = bytes[i] + for i in [0..4[ do cpixels[offset+i] = bytes[i].to_b loaded = false end @@ -177,12 +177,12 @@ class CustomTexture do # Simple conversion from [0.0..1.0] to [0..255] var bytes = [for c in color do (c*255.0).round.to_i.clamp(0, 255).to_bytes.last] - while bytes.length < 4 do bytes.add 255u8 + while bytes.length < 4 do bytes.add 255 var i = 0 for x in [0..width.to_i[ do for y in [0..height.to_i[ do - for j in [0..4[ do cpixels[i+j] = bytes[j] + for j in [0..4[ do cpixels[i+j] = bytes[j].to_b i += 4 end end diff --git a/lib/github/README.md b/lib/github/README.md index 041e753..18814ee 100644 --- a/lib/github/README.md +++ b/lib/github/README.md @@ -18,17 +18,17 @@ Token can also be recovered from user config with `get_github_oauth`. [[doc: load_user]] [[doc: User]] -[[list: User]] +[[defs: User]] ### Retrieving repo data [[doc: load_repo]] [[doc: Repo]] -[[list: Repo]] +[[defs: Repo]] ### Other data -[[list: github::api]] +[[defs: github::api]] ### Advanced uses @@ -68,4 +68,4 @@ GithubAPI can trigger different events depending on the hook configuration. [[doc: GithubEvent]] -[[list: github::events]] +[[defs: github::events]] diff --git a/lib/html/bootstrap.nit b/lib/html/bootstrap.nit index cc3d6e2..3e12dd7 100644 --- a/lib/html/bootstrap.nit +++ b/lib/html/bootstrap.nit @@ -72,7 +72,7 @@ class Link redef fun rendering do add "{text}" end end diff --git a/lib/json/static.nit b/lib/json/static.nit index 0d25f10..2d42e16 100644 --- a/lib/json/static.nit +++ b/lib/json/static.nit @@ -128,7 +128,7 @@ redef class FlatText redef fun json_need_escape do var its = items for i in [first_byte .. last_byte] do - if its[i] == 0x5Cu8 then return true + if its[i] == 0x5C then return true end return false end diff --git a/lib/libevent/libevent.nit b/lib/libevent/libevent.nit index efd434f..ec7d290 100644 --- a/lib/libevent/libevent.nit +++ b/lib/libevent/libevent.nit @@ -2,6 +2,7 @@ # # Copyright 2013 Jean-Philippe Caissy # Copyright 2014 Alexis Laferrière +# Copyright 2018 Matthieu Le Guellaut # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -38,6 +39,8 @@ in "C" `{ #include #include #include + #include + #include // Protect callbacks for compatibility with light FFI #ifdef Connection_decr_ref @@ -145,8 +148,6 @@ interface EventCallback end # Spawned to manage a specific connection -# -# TODO, use polls class Connection super Writer @@ -366,7 +367,7 @@ extern class NativeBufferEvent `{ struct bufferevent * `} `} # Write the byte `value` - fun write_byte(value: Byte): Int `{ + fun write_byte(value: Int): Int `{ unsigned char byt = (unsigned char)value; return bufferevent_write(self, &byt, 1); `} @@ -418,31 +419,49 @@ end # A listener acting on an interface and port, spawns `Connection` on new connections extern class ConnectionListener `{ struct evconnlistener * `} - private new bind_to(base: NativeEventBase, address: CString, port: Int, factory: ConnectionFactory) + private new bind_tcp(base: NativeEventBase, address: CString, port: Int, factory: ConnectionFactory) import ConnectionFactory.accept_connection, error_callback `{ - struct sockaddr_in sin; - struct evconnlistener *listener; ConnectionFactory_incr_ref(factory); struct hostent *hostent = gethostbyname(address); - if (!hostent) { return NULL; } - memset(&sin, 0, sizeof(sin)); + struct sockaddr_in sin = {0}; sin.sin_family = hostent->h_addrtype; sin.sin_port = htons(port); memcpy( &(sin.sin_addr.s_addr), (const void*)hostent->h_addr, hostent->h_length ); - listener = evconnlistener_new_bind(base, + struct evconnlistener *listener = evconnlistener_new_bind(base, (evconnlistener_cb)accept_connection_cb, factory, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, -1, (struct sockaddr*)&sin, sizeof(sin)); + if (listener != NULL) { + evconnlistener_set_error_cb(listener, + (evconnlistener_errorcb)ConnectionListener_error_callback); + } + + return listener; + `} + + private new bind_unix(base: NativeEventBase, file: CString, factory: ConnectionFactory) + import ConnectionFactory.accept_connection, error_callback `{ + + ConnectionFactory_incr_ref(factory); + + struct sockaddr_un sun = {0}; + sun.sun_family = AF_UNIX; + strncpy(sun.sun_path, file, sizeof(sun.sun_path) - 1); + struct evconnlistener *listener = evconnlistener_new_bind(base, + (evconnlistener_cb)accept_connection_cb, factory, + LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, -1, + (struct sockaddr*)&sun, sizeof(sun)); if (listener != NULL) { - evconnlistener_set_error_cb(listener, (evconnlistener_errorcb)ConnectionListener_error_callback); + evconnlistener_set_error_cb(listener, + (evconnlistener_errorcb)ConnectionListener_error_callback); } return listener; @@ -451,15 +470,17 @@ extern class ConnectionListener `{ struct evconnlistener * `} # Get the `NativeEventBase` associated to `self` fun base: NativeEventBase `{ return evconnlistener_get_base(self); `} - # Callback method on listening error - fun error_callback do + # Callback on listening error + fun error_callback + do var cstr = evutil_socket_error_to_string(evutil_socket_error) - print_error "libevent error: '{cstr}'" + print_error "libevent error: {cstr}" end end # Factory to listen on sockets and create new `Connection` class ConnectionFactory + # The `NativeEventBase` for the dispatch loop of this factory var event_base: NativeEventBase @@ -490,17 +511,45 @@ class ConnectionFactory return new Connection(buffer_event) end - # Listen on `address`:`port` for new connection, which will callback `spawn_connection` - fun bind_to(address: String, port: Int): nullable ConnectionListener + # Listen on the TCP socket at `address`:`port` for new connections + # + # On new connections, libevent callbacks `spawn_connection`. + fun bind_tcp(address: String, port: Int): nullable ConnectionListener do - var listener = new ConnectionListener.bind_to(event_base, address.to_cstring, port, self) + var listener = new ConnectionListener.bind_tcp( + event_base, address.to_cstring, port, self) + if listener.address_is_null then - sys.stderr.write "libevent warning: Opening {address}:{port} failed\n" + print_error "libevent warning: Opening {address}:{port} failed, " + + evutil_socket_error_to_string(evutil_socket_error).to_s + return null end + return listener end - # Put string representation of source `address` into `buf` + # Listen on a UNIX domain socket for new connections + # + # On new connections, libevent callbacks `spawn_connection`. + fun bind_unix(path: String): nullable ConnectionListener + do + # Delete the socket if it already exists + var stat = path.file_stat + if stat != null and stat.is_sock then path.file_delete + + var listener = new ConnectionListener.bind_unix( + event_base, path.to_cstring, self) + + if listener.address_is_null then + print_error "libevent warning: Opening UNIX domain socket {path} failed, " + + evutil_socket_error_to_string(evutil_socket_error).to_s + return null + end + + return listener + end + + # Put a human readable string representation of `address` into `buf` private fun addrin_to_address(address: Pointer, buf: CString, buf_len: Int): CString `{ struct sockaddr *addrin = (struct sockaddr*)address; @@ -512,6 +561,14 @@ class ConnectionFactory struct in6_addr *src = &((struct sockaddr_in6*)addrin)->sin6_addr; return (char *)inet_ntop(addrin->sa_family, src, buf, buf_len); } + else if (addrin->sa_family == AF_UNIX) { + struct sockaddr_un *src = (struct sockaddr_un*)addrin; + char *path = src->sun_path; + if (path == NULL) return "Unnamed UNIX domain socket"; + if (path[0] == '\0') return "Abstract UNIX domain socket"; + return path; + } + return NULL; `} end diff --git a/lib/libevent/libevent_example.nit b/lib/libevent/libevent_example.nit new file mode 100644 index 0000000..c00917e --- /dev/null +++ b/lib/libevent/libevent_example.nit @@ -0,0 +1,57 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Minimal usage example of libevent +module libevent_example is example + +import libevent + +# Factory creating instances of `EchoConnection` to handle new connections +class MyFactory + super ConnectionFactory + + redef fun spawn_connection(buf, address) + do + return new EchoConnection(buf) + end +end + +# Connection echoing data received from clients back at them +class EchoConnection + super Connection + + redef fun read_callback(content) + do + print "Received: {content}" + write content + end +end + +# Skip the actual execution when testing +if "NIT_TESTING".environ == "true" then exit 0 + +# Setup libevent system +var event_base = new NativeEventBase +var factory = new MyFactory(event_base) + +# Open a TCP socket for listening +factory.bind_tcp("localhost", 8888) + +# Open a UNIX domain socket for listening +factory.bind_unix("/tmp/my.sck") + +# Launch event loop +event_base.dispatch + +event_base.free diff --git a/lib/libevent/libevent_test.nit b/lib/libevent/libevent_test.nit new file mode 100644 index 0000000..4c64b2e --- /dev/null +++ b/lib/libevent/libevent_test.nit @@ -0,0 +1,94 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module libevent_test + +import libevent +import pthreads + +redef class Sys + + var testing_id: Int is lazy do + var id = "NIT_TESTING_ID".environ + return if id.is_empty then 0 else id.to_i + end + + # Config for test sockets + var tcp_addr = "localhost" + var tcp_port: Int = 20000 + testing_id + var unix_socket_path = "/tmp/libevent_test{testing_id}.sck" +end + +class TestConnectionFactory + super ConnectionFactory + + redef fun spawn_connection(buf, address) + do + print "[Server] New client: {address}" + + var conn = new TestConnection(buf) + print "[Server] Write: Hi" + conn.write "Hi\n" + return conn + end +end + +class TestConnection + super Connection + + redef fun read_callback(content) + do + 0.2.sleep # Forcing the server output after the client output + printn "[Server] Read: {content}" + end +end + +class ServerThread + super Thread + + redef fun main + do + var event_base = new NativeEventBase + var factory = new TestConnectionFactory(event_base) + + # Bind TCP socket + factory.bind_tcp(tcp_addr, tcp_port) + + # Bind UNIX domain socket + factory.bind_unix unix_socket_path + + event_base.dispatch + event_base.free + + return null + end +end + +redef fun system(cmd) +do + if testing_id == 0 then print "[Client] {cmd}" + return super(cmd) +end + +# First, launch a server in the background +var server = new ServerThread +server.start +0.1.sleep + +# Test what should succeed +system "echo 'Hello TCP' | nc -N {tcp_addr} {tcp_port}" +system "echo 'Hello UNIX' | nc -NU {unix_socket_path}" + +1.0.sleep +exit 0 diff --git a/lib/libevent/package.ini b/lib/libevent/package.ini index c24d489..38f78e9 100644 --- a/lib/libevent/package.ini +++ b/lib/libevent/package.ini @@ -1,6 +1,6 @@ [package] name=libevent -tags=wrapper,lib +tags=network,wrapper,lib maintainer=Alexis Laferrière license=Apache-2.0 desc=Low-level wrapper around the libevent library to manage events on file descriptors diff --git a/lib/markdown2/markdown2.nit b/lib/markdown2/markdown2.nit new file mode 100644 index 0000000..85da1b9 --- /dev/null +++ b/lib/markdown2/markdown2.nit @@ -0,0 +1,27 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module markdown2 + +import markdown_block_parsing +import markdown_html_rendering + +redef class String + fun md_to_html2: String do + var parser = new MdParser + var doc = parser.parse(self) + var renderer = new HtmlRenderer + return renderer.render(doc) + end +end diff --git a/lib/markdown2/markdown_ast.nit b/lib/markdown2/markdown_ast.nit new file mode 100644 index 0000000..3de2196 --- /dev/null +++ b/lib/markdown2/markdown_ast.nit @@ -0,0 +1,487 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Markdown AST representation +module markdown_ast + +# An abstract node +abstract class MdNode + + # Node location in original markdown + var location: MdLocation + + # Node parent + var parent: nullable MdNode = null is writable + + # First child + var first_child: nullable MdNode = null is writable + + # Last child + var last_child: nullable MdNode = null is writable + + # Previous node + var prev: nullable MdNode = null is writable + + # Next node + var next: nullable MdNode = null is writable + + # Children nodes of `self` + fun children: Array[MdNode] do + var nodes = new Array[MdNode] + + var node = first_child + while node != null do + nodes.add node + node = node.next + end + + return nodes + end + + # Append a child to `self` + fun append_child(child: MdNode) do + child.unlink + child.parent = self + if last_child != null then + last_child.as(not null).next = child + child.prev = last_child + last_child = child + else + first_child = child + last_child = child + end + end + + # Prepend a child to `self` + fun prepend_child(child: MdNode) do + child.unlink + child.parent = self + if first_child != null then + first_child.as(not null).prev = child + child.next = first_child + first_child = child + else + first_child = child + last_child = child + end + end + + # Unlink `self` from its `parent` + fun unlink do + if prev != null then + prev.as(not null).next = next + else if parent != null then + parent.as(not null).first_child = next + end + if next != null then + next.as(not null).prev = prev + else if parent != null then + parent.as(not null).last_child = prev + end + parent = null + next = null + prev = null + end + + # Insert `sibling` after `self`. + fun insert_after(sibling: MdNode) do + sibling.unlink + sibling.next = next + if sibling.next != null then + sibling.next.as(not null).prev = sibling + end + sibling.prev = self + next = sibling + sibling.parent = parent + if sibling.next == null then + sibling.parent.as(not null).last_child = sibling + end + end + + # Insert `sibling` before `self`. + fun insert_before(sibling: MdNode) do + sibling.unlink + sibling.prev = prev + if sibling.prev != null then + sibling.prev.as(not null).next = sibling + end + sibling.next = self + prev = sibling + sibling.parent = parent + if sibling.prev == null then + sibling.parent.as(not null).first_child = sibling + end + end + + # Visit all children or `self` + fun visit_all(v: MdVisitor) do + var node = first_child + while node != null do + var next = node.next + v.visit(node) + node = next + end + end + + redef fun to_s do return "{super}\{{to_s_attrs}\}" + + # Returns `self` attributes as a String + # + # Mainly used for debug purposes. + fun to_s_attrs: String do return "loc: {location}" + + # Print `self` AST + fun debug do + var v = new MdASTPrinter + v.enter_visit(self) + end +end + +# A visitor for Markdown AST +interface MdVisitor + + # Start visiting `node` + fun enter_visit(node: MdNode) do visit(node) + + # Visit `node` + # + # Method to define in specific visitor. + # It should not be called directly but used by `enter_visit`. + protected fun visit(node: MdNode) is abstract +end + +# Print the AST content +class MdASTPrinter + super MdVisitor + + # Current indent level + var indent = 0 + + # Visit `self` to print the AST content + fun print_ast(node: MdNode) do + print "{" " * indent}{node}" + indent += 1 + node.visit_all(self) + indent -= 1 + end + + redef fun visit(node) do print_ast(node) +end + +# Blocks + +# An abstract markdown block +abstract class MdBlock + super MdNode + + redef fun parent do return super + + # Can this block contain other blocks? + var is_container = false + + # Can this block contain `block`? + fun can_contain(block: MdBlock): Bool do return false + + # Parents of blocks can only be blocks + redef fun parent=(node) do + assert parent == null or parent isa MdBlock else + print "Parent of block must also be block." + end + super(node) + end +end + +# A Markdown document +class MdDocument + super MdBlock + + redef var is_container = true + + redef fun can_contain(block) do return true +end + +# A block quote +class MdBlockQuote + super MdBlock + + redef var is_container = true + + redef fun can_contain(block) do return true +end + +# A block of code (indented or fenced) +abstract class MdCodeBlock + super MdBlock + + # Literal content + var literal: nullable String = null is writable + + # Fence info / meta + var info: nullable String = null is writable + + redef fun to_s_attrs do return "{super}, info={info or else "null"}, literal={literal or else "null"}" +end + +# A block code that starts with an indent +class MdIndentedCodeBlock + super MdCodeBlock + + # Does this block use tabs instead of spaces? + var use_tabs: Bool + + redef fun to_s_attrs do return "{super}, use_tabs={use_tabs}" +end + +# A code block that starts with a fence +class MdFencedCodeBlock + super MdCodeBlock + + # Fence character + var fence_char: Char + + # Fence length + var fence_length: Int + + # Fence indentation level + var fence_indent: Int + + redef fun to_s_attrs do return "{super}, fence_char={fence_char}, fence_length={fence_length}, fence_indent={fence_indent}" +end + +# A heading +class MdHeading + super MdBlock + + # Heading level (from 1 to 6) + var level: Int + + # Is this heading in the setext format in the original source? + var is_setext = false is optional + + # Does this heading has an atx trailing in the original source? + var has_atx_trailing = false is optional + + redef fun to_s_attrs do return "{super}, level={level}" +end + +# An html block +class MdHtmlBlock + super MdBlock + + # Literal content + var literal: nullable String = null is writable + + redef fun to_s_attrs do return "{super}, literal={literal or else "null"}" +end + +# An ordered or unordered list block +abstract class MdListBlock + super MdBlock + + # Does this list contains line breaks? + var is_tight: Bool = false is writable + + redef var is_container = true + + redef fun can_contain(block) do return block isa MdListItem + + redef fun to_s_attrs do return "{super}, is_tight={is_tight}" +end + +# An ordered or unordered list item block +class MdListItem + super MdBlock + + redef var is_container = true + + redef fun can_contain(block) do return true +end + +# An ordered list block +class MdOrderedList + super MdListBlock + + # List starting number + var start_number: Int + + # List number delimiter + var delimiter: Char + + redef fun to_s_attrs do return "{super}, start_number={start_number}, delimiter={delimiter}" +end + +# An unordered list +class MdUnorderedList + super MdListBlock + + # List bullet marker + var bullet_marker: Char + + redef fun to_s_attrs do return "{super}, bullet_marker={bullet_marker}" +end + +# A paragraph block +class MdParagraph + super MdBlock + + # Is this paragraph in a list? + fun is_in_list: Bool do + var parent = self.parent + return parent != null and parent.parent isa MdListBlock + end + + # Is this paragraph in a tight list? + fun is_in_tight_list: Bool do + var parent = self.parent + if parent == null then return false + var gramps = parent.parent + return gramps isa MdListBlock and gramps.is_tight + end +end + +# A ruler +class MdThematicBreak + super MdBlock + + # Thematic break pattern used in markdown source + var original_pattern: String +end + +# Inline nodes + +# A line break (soft or hard) +abstract class MdLineBreak + super MdNode +end + +# A hardline break (`\\n` or ` \n`) +class MdHardLineBreak + super MdLineBreak + + # Does this line break used a backslash in the original source? + var has_backslash: Bool +end + +# A soft line breack (`\r` or `\n`) +class MdSoftLineBreak + super MdLineBreak +end + +# An inline code string +class MdCode + super MdNode + + # Emphasis delimiter + var delimiter: String + + # Literal content + var literal: String is writable + + redef fun to_s_attrs do return "{super}, literal={literal}" +end + +# A node that users delimiters in the Markdown form +# +# For example the emphasis: `*bold*`. +abstract class MdDelimited + super MdNode + + # Emphasis delimiter + var delimiter: String + + # Opening delimiter + fun opening_delimiter: String do return delimiter + + # Closing delimiter + fun closing_delimiter: String do return delimiter + + redef fun to_s_attrs do return "{super}, delimiter={delimiter}" +end + +# An emphasis +class MdEmphasis + super MdDelimited +end + +# A strong emphasis token +class MdStrongEmphasis + super MdDelimited +end + +# An inlined html string +class MdHtmlInline + super MdNode + + # Literal content + var literal: String is writable + + redef fun to_s_attrs do return "{super}, literal={literal}" +end + +# A link or image +abstract class MdLinkOrImage + super MdNode + + # Link destination + var destination: String is writable + + # Link title + var title: nullable String is writable + + # Is the `destination` between pointy brackets `` + var has_brackets = false is writable + + redef fun to_s_attrs do return "{super}, destination={destination}, title={title or else "null"}" +end + +# An image +class MdImage + super MdLinkOrImage +end + +# A link +class MdLink + super MdLinkOrImage + + # Is this link an autolink? + var is_autolink = false is optional, writable +end + +# A raw text token +class MdText + super MdNode + + # Literal content + var literal: String is writable + + redef fun to_s_attrs do return "{super}, literal={literal}" +end + +# MdNode location in the Markdown input +class MdLocation + + # Starting line number (starting from 1). + var line_start: Int is writable + + # Starting column number (starting from 1). + var column_start: Int is writable + + # Stopping line number (starting from 1). + var line_end: Int is writable + + # Stopping column number (starting from 1). + var column_end: Int is writable + + redef fun to_s do return "{line_start},{column_start}--{line_end},{column_end}" +end diff --git a/lib/markdown2/markdown_block_parsing.nit b/lib/markdown2/markdown_block_parsing.nit new file mode 100644 index 0000000..cfa07b5 --- /dev/null +++ b/lib/markdown2/markdown_block_parsing.nit @@ -0,0 +1,1503 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Markdown blocks parsing +# +# Introduce the parsers for the different Markdown blocks such as headings, lists +# code blocks etc. +module markdown_block_parsing + +import markdown_inline_parsing + +# Markdown parser +# +# Used to create the AST representation of a Markdown document. +class MdParser + + # Inline parser used to parse block content + private var inline_parser = new MdInlineParser is lazy + + # Block parsers factories + private var block_parser_factories: Collection[MdBlockParserFactory] do + var factories = new Array[MdBlockParserFactory] + factories.add new MdBlockQuoteParserFactory + factories.add new MdHeadingParserFactory + factories.add new MdFencedCodeBlockParserFactory + factories.add new MdHtmlBlockParserFactory + factories.add new MdThematicBreakParserFactory + factories.add new MdListBlockParserFactory + factories.add new MdIndentedCodeBlockParserFactory + return factories + end + + # Active block parsers + # + # Used as a stack to parse nested blocks. + private var active_block_parsers = new Array[MdBlockParser] + + # All active block parsers + private var all_block_parsers = new HashSet[MdBlockParser] + + # Return the active block parser + # + # The last entry in the `active_block_parsers` stack. + private fun active_block_parser: MdBlockParser do + return active_block_parsers.last + end + + # Activate a `block_parser` + # + # Add the `block_parser` on the top of the `active_block_parsers` stack. + # Also register it in `all_block_parsers`. + private fun activate_block_parser(block_parser: MdBlockParser) do + active_block_parsers.add block_parser + all_block_parsers.add block_parser + end + + # Deactivate the `active_block_parser` + private fun deactivate_block_parser do + active_block_parsers.pop + end + + # Deactivate and remove the `active_block_parser` from the `all_block_parsers` list + private fun remove_active_block_parser do + var old = active_block_parser + deactivate_block_parser + all_block_parsers.remove(old) + old.block.unlink + end + + # Post-processors applied after the parsing of a document + var post_processors = new Array[MdPostProcessor] is writable + + # Currently parsed line + private var line_string: String is noinit + + # Current index (offset) in input `line_string` (starts at 0) + private var index = 0 + + # Current column in input `line_string` (starts at 0) + # + # Tab causes column to go to next 4-space tab stop. + private var column = 0 + + # Is the current column within a tab character (partially consumed tab) + private var column_is_in_tab: Bool is noinit + + # Current line in input string (starts at 1) + private var line = 1 + + # Index of the next non-space character starting from `index` + private var next_non_space_index = 0 + + # Next non-space column + private var next_non_space_column = 0 + + # Current indent in columns + # + # Either by spaces or tab stop of 4, starting from `column`. + private var indent = 0 + + # Is the current `line` blank starting from `index`? + private var is_blank: Bool is noinit + + # Does a node end with a blank line? + private var last_line_blank = new HashMap[MdNode, Bool] + + # Initialize parser state + private fun initialize do + active_block_parsers.clear + all_block_parsers.clear + index = 0 + column = 0 + column_is_in_tab = false + line = 1 + next_non_space_index = 0 + next_non_space_column = 0 + indent = 0 + is_blank = false + last_line_blank.clear + end + + # Parse the `input` string as a MdDocument + fun parse(input: String): MdDocument do + initialize + + var document_block_parser = new MdDocumentBlockParser(1, 1, 0) + activate_block_parser(document_block_parser) + var line_start = 0 + var line_break = find_line_break(input, line_start) + while line_break != -1 do + var line_string = input.substring(line_start, line_break - line_start) + incorporate_line(line_string) + if line_break + 1 < input.length and + input.chars[line_break] == '\r' and + input.chars[line_break + 1] == '\n' then + line_start = line_break + 2 + else + line_start = line_break + 1 + end + line_break = find_line_break(input, line_start) + line += 1 + column = 0 + end + + # Finalize pending line + if input.length > 0 and (line_start == 0 or line_start < input.length) then + incorporate_line(input.substring(line_start, input.length - line_start)) + end + finalize_blocks(active_block_parsers) + + # Walk through a block and its chiildren revursively + # Parsing string content into inline content where appropriate. + var all_block_parsers = all_block_parsers.to_a + var i = all_block_parsers.length - 1 + while i >= 0 do + var block_parser = all_block_parsers[i] + block_parser.parse_inlines(inline_parser) + i -= 1 + end + var document = document_block_parser.block + return document + end + + # Post-process the `document` + fun post_process(document: MdDocument) do + for processor in post_processors do + processor.post_process(self, document) + end + end + + # Analyze a line of text and update the document + # + # We parse Markdown text by calling this on each line of `input`. + private fun incorporate_line(input: String) do + line_string = input + index = 0 + column = 0 + column_is_in_tab = false + + # For each containing block, try to parse the associated line start. + var matches = 1 + for i in [1 .. active_block_parsers.length[ do + var block_parser = active_block_parsers[i] + find_next_non_space + + var result = block_parser.try_continue(self) + if result isa MdBlockContinue then + if result.is_finalize then + block_parser.finalize(self) + return + else + if result.new_index != -1 then + set_new_index result.new_index + else if result.new_column != -1 then + set_new_column result.new_column + end + end + matches += 1 + else + break + end + end + + var unmatched_block_parsers = active_block_parsers.subarray( + matches, active_block_parsers.length - matches) + var last_matched_block_parser = active_block_parsers[matches - 1] + var block_parser = last_matched_block_parser + var all_closed = unmatched_block_parsers.is_empty + + # Unless last matched container is a code block, try new container starts, + # adding children to the last matched container. + var try_block_starts = block_parser.block isa MdParagraph or + block_parser.block.is_container + + while try_block_starts do + find_next_non_space + + # Optimize lookup + if is_blank or (indent < 4 and line_string.chars[next_non_space_index].is_letter) then + set_new_index next_non_space_index + break + end + + var block_start = find_block_start(block_parser) + if block_start == null then + set_new_index next_non_space_index + break + end + + if not all_closed then + finalize_blocks(unmatched_block_parsers) + all_closed = true + end + + if block_start.new_index != -1 then + set_new_index block_start.new_index + else if block_start.new_column != -1 then + set_new_column block_start.new_column + end + + if block_start.replace_active_block_parser then + remove_active_block_parser + end + + for new_block_parser in block_start.block_parsers do + add_child(new_block_parser) + block_parser = new_block_parser + try_block_starts = new_block_parser.block.is_container + end + end + + # What remains at the offset is a text line. + # Add the text to the appropriate block. + + # First check for a lazy paragraph continuation + if not all_closed and not is_blank and active_block_parser isa MdParagraphParser then + add_line + else + # Finalize any blocks not matched + if not all_closed then + finalize_blocks(unmatched_block_parsers) + end + propagate_last_line_blank(block_parser, last_matched_block_parser) + + if not block_parser.block.is_container then + add_line + else if not is_blank then + # Create a paragraph container for the line + add_child(new MdParagraphParser(line, column + 1, block_parser.content_offset)) + add_line + end + end + end + + # Find what kind of block starts at `index` in `input` + private fun find_block_start(block_parser: MdBlockParser): nullable MdBlockStart do + for block_parser_factory in block_parser_factories do + var result = block_parser_factory.try_start(self, block_parser) + if result != null then return result + end + return null + end + + # Add a `block_parser` block's as child of the active block parser block + private fun add_child(block_parser: MdBlockParser) do + # Finalize non-parentable blocks + while not active_block_parser.block.can_contain(block_parser.block) do + active_block_parser.finalize(self) + end + # Append block block parser block to its parent + active_block_parser.block.append_child(block_parser.block) + activate_block_parser(block_parser) + end + + # Add line content to the active block parser + # + # We assume it can accept lines. + private fun add_line do + var content = null + if column_is_in_tab then + # Out column is in a partially consumed tab. + # Expand the remaining columns to the next tab stop to spaces. + var after_tab = index + 1 + var rest = line_string.substring(after_tab, line_string.length - after_tab) + var spaces = column.columns_to_next_tab_stop + var buffer = new Buffer + for i in [0 .. spaces[ do + buffer.add ' ' + end + buffer.append(rest) + content = buffer.write_to_string + else + content = line_string.substring(index, line_string.length - index) + end + active_block_parser.add_line(content) + end + + # Finalize blocks of previous line + private fun finalize_blocks(block_parsers: Sequence[MdBlockParser]) do + var i = block_parsers.length - 1 + while i >= 0 do + var block_parser = block_parsers[i] + block_parser.finalize(self) + i -= 1 + end + end + + # Advance the `index` position to the next character + # + # Also set the `column`. + # If the next character is a tab, compute the new column accordingly. + private fun advance do + var c = line_string.chars[index] + if c == '\t' then + index += 1 + column += column.columns_to_next_tab_stop + else + index += 1 + column += 1 + end + end + + # Move `index` to the next non-space character index in the `input` string + # + # Also set `next_non_space_index`, `next_non_space_column`, `is_blank` and `indent`. + private fun find_next_non_space do + var i = index + var cols = column + + is_blank = true + while i < line_string.length do + var c = line_string.chars[i] + if c == ' ' then + i += 1 + cols += 1 + continue + else if c == '\t' then + i += 1 + cols += 4 - (cols % 4) + continue + end + is_blank = false + break + end + + next_non_space_index = i + next_non_space_column = cols + indent = next_non_space_column - column + end + + # Return the position of the next line break + # + # We consider `\r` and `\n`. + private fun find_line_break(input: String, start_index: Int): Int do + for i in [start_index .. input.length[ do + var char = input.chars[i] + if char == '\r' or char == '\n' then return i + end + return -1 + end + + # Set the parser `index` at `new_index` + # + # Also set `column` and `column_is_in_tab`. + private fun set_new_index(new_index: Int) do + if new_index >= next_non_space_index then + # We can start from here, no need to calculate tab stops again + index = next_non_space_index + column = next_non_space_column + end + while index < new_index and index != line_string.length do + advance + end + # If we're going to an index as opposed to a column, we're never within a tab + column_is_in_tab = false + end + + # Set the parser `column` at `new_column` + # + # Also set `index` and `column_is_in_tab`. + private fun set_new_column(new_column: Int) do + if new_column >= next_non_space_column then + # We can start from here, no need to calculate tab stops again + index = next_non_space_index + column = next_non_space_column + end + while column < new_column and index != line_string.length do + advance + end + if column > new_column then + # Last character was a tab and we overshot our target + index -= 1 + column = new_column + column_is_in_tab = true + else + column_is_in_tab = false + end + end + + # Does `block` end with a blank line? + private fun ends_with_blank_line(block: nullable MdNode): Bool do + while block != null do + if is_last_line_blank(block) then return true + if block isa MdListBlock or block isa MdListItem then + block = block.last_child + else + break + end + end + return false + end + + # Propagate a blank line to all block_parser blocl's parents + private fun propagate_last_line_blank(block_parser: MdBlockParser, last_matched_block_parser: MdBlockParser) do + var last_child = block_parser.block.last_child + if is_blank and last_child != null then + last_line_blank[last_child] = true + end + var block = block_parser.block + + # Block quotes lines are never blank as they start with `>`. + # We don't count blanks in fenced code for purposes of thight/loose lists. + # We also don't set `last_line_blank` on an empty list item. + var last_line_blank = is_blank and + not (block isa MdBlockQuote or + block isa MdFencedCodeBlock or + (block isa MdListItem and block.first_child == null and + block_parser != last_matched_block_parser)) + + # Propagate `last_line_blank` up through parents + var node: nullable MdNode = block_parser.block + while node != null do + self.last_line_blank[node] = last_line_blank + node = node.parent + end + end + + # Is last line blank for `node`? + private fun is_last_line_blank(node: MdNode): Bool do + if not last_line_blank.has_key(node) then return false + return last_line_blank[node] + end +end + +# Block parsing + +# Parser for a specific block node +abstract class MdBlockParser + + # Kind of block under construction + type BLOCK: MdBlock + + # MdBlock under construction + fun block: BLOCK is abstract + + # Line Start + var line_start: Int + + # Column start + var column_start: Int + + # Location at start + # + # The location end it initialized at `-1` and will be set later in the + # `finalize` method. + var location: MdLocation is lazy do return new MdLocation(line_start, column_start, -1, -1) + + # Column where the content starts + var content_offset: Int + + # Initialize the current `block` + fun initialize(parser: MdParser) do end + + # Can `self` continue from the current `index` in `parser`? + # + # Return a new `MdBlockContinue` if `self` can continue parsing. + # Return null otherwise. + fun try_continue(state: MdParser): nullable MdBlockContinue is abstract + + # Add `line` to the current `block` + fun add_line(line: String) do end + + # Finalize the current `block` + # + # Deactivate `self` from `parser` and call `close_block`. + fun finalize(parser: MdParser) do + if parser.active_block_parser == self then + parser.deactivate_block_parser + end + end + + # Parse `block` lines + fun parse_inlines(inline_parser: MdInlineParser) do end +end + +# Result object for continuing parsing of a block +class MdBlockContinue + + # Index from which continue parsing + var new_index: Int + + # Column from which continue parsing + var new_column: Int + + # Is the block finalized? + var is_finalize: Bool + + # Continue from index + init at_index(new_index: Int) do + init(new_index, -1, false) + end + + # Continue from column + init at_column(new_column: Int) do + init(-1, new_column, false) + end + + # Block is finished + init finished do + init(-1, -1, true) + end +end + +# Block parser factory for a block node for determining when a block starts +abstract class MdBlockParserFactory + + # Can the associated block parser can start at the current line in `parser`? + # + # Return a new `MdBlockStart` if the block parser can start. + # Return null otherwise. + fun try_start(parser: MdParser, matched_block_parser: MdBlockParser): + nullable MdBlockStart is abstract +end + +# Result object from starting parsing of a block +class MdBlockStart + + # Block parsers for this block start + var block_parsers: Array[MdBlockParser] + + # Index where the parsing should start + var new_index = -1 + + # Column where the parsing should start + var new_column = -1 + + # Does the block starting with `self` terminate a previous block? + var replace_active_block_parser = false + + # Start from `new_index` + fun at_index(new_index: Int): MdBlockStart do + self.new_index = new_index + return self + end + + # Start from `new_column` + fun at_column(new_column: Int): MdBlockStart do + self.new_column = new_column + return self + end + + # Start replacing the active block parser + fun replacing_active_block_parser: MdBlockStart do + self.replace_active_block_parser = true + return self + end +end + +# Parser for the whole document +class MdDocumentBlockParser + super MdBlockParser + + redef type BLOCK: MdDocument + redef var block = new MdDocument(location) is lazy + + # Always continue at current indent + redef fun try_continue(state) do return new MdBlockContinue.at_index(state.index) + + redef fun finalize(parser) do + end + + # redef fun finalize(state) do + redef fun parse_inlines(inline_parser) do + var last_child = block.last_child + if last_child != null then + location.line_end = last_child.location.line_end + location.column_end = last_child.location.column_end + end + end +end + +# Headings parser +class MdHeadingParser + super MdBlockParser + + redef type BLOCK: MdHeading + + redef var block = new MdHeading(location, level, is_setext, has_atx_trailing) is lazy + + redef var location = new MdLocation(line_start, column_start, line_end, column_end) is lazy + + # Line end + var line_end: Int + + # Column end + var column_end: Int + + # Heading level + var level: Int + + # Heading content + var content: String + + # Heading has ATX trailing + var has_atx_trailing: Bool + + # Heading is setext format + var is_setext: Bool + + # Never continue parsing as an heading is a one liner + redef fun try_continue(state) do return null + + # Parse the heading content + redef fun parse_inlines(inline_parser) do + inline_parser.parse(content, content_offset, block) + end +end + +# Heading parser factory +class MdHeadingParserFactory + super MdBlockParserFactory + + redef fun try_start(state, matched_block_parser) do + if state.indent >= 4 then return null + + var next_non_space = state.next_non_space_index + var line = state.line_string + var paragraph = null + if matched_block_parser isa MdParagraphParser then + paragraph = matched_block_parser.content + end + + var line_content = line.substring(next_non_space, line.length - next_non_space) + var match = line_content.search(re_atx_heading) + if match != null then + # ATX heading + var new_offset = next_non_space + match.subs.first.as(not null).length + var level = match.subs.first.as(not null).to_s.trim.length + # remove trailing ###s + var after_leading = line.substring(new_offset, line.length - new_offset) + var trailing = after_leading.search(re_atx_trailing) + var has_trailing = trailing != null + var trailing_length = if trailing != null then trailing.length else 0 + var content = after_leading.replace(re_atx_trailing, "") + return (new MdBlockStart( + [new MdHeadingParser( + state.line, + next_non_space + 1, + new_offset + 1, + state.line, + new_offset + content.length + trailing_length, + level, + content, + has_trailing, false)]) + ).at_index(line.length) + end + + if paragraph == null then return null + + match = line_content.search(re_setext_heading) + if match == null then return null + var level = 2 + if match.subs.first.as(not null).to_s.chars.first == '=' then level = 1 + var content = paragraph.to_s + return (new MdBlockStart( + [new MdHeadingParser( + state.line - 1, + next_non_space + 1, + 0, + state.line, + state.column + match.length, + level, + content, + false, true)]) + ).at_index(line.length).replacing_active_block_parser + end +end + +# Blockquotes parser +class MdBlockQuoteParser + super MdBlockParser + + redef type BLOCK: MdBlockQuote + redef var block = new MdBlockQuote(location) is lazy + + redef fun try_continue(state) do + var next_non_space = state.next_non_space_index + var indent = state.indent + var line = state.line_string + + if indent >= 4 then return null + if next_non_space >= line.length then return null + if line.chars[next_non_space] != '>' then return null + + var new_column = state.column + state.indent + 1 + # optional following space or tab + if state.line_string.is_space_or_tab(next_non_space + 1) then + new_column += 1 + end + return new MdBlockContinue.at_column(new_column) + end + + redef fun parse_inlines(inline_parser) do + var last_child = block.last_child + if last_child != null then + location.line_end = last_child.location.line_end + location.column_end = last_child.location.column_end + end + end +end + +# Blockquotes parser factory +class MdBlockQuoteParserFactory + super MdBlockParserFactory + + redef fun try_start(state, matched_block_parser) do + var next_non_space = state.next_non_space_index + var indent = state.indent + var line = state.line_string + + if indent >= 4 then return null + if next_non_space >= line.length then return null + if line.chars[next_non_space] != '>' then return null + + var new_column = state.column + state.indent + 1 + # optional following space or tab + if state.line_string.is_space_or_tab(next_non_space + 1) then + new_column += 1 + end + return (new MdBlockStart( + [new MdBlockQuoteParser( + state.line, + state.column + 1, + new_column)]) + ).at_column(new_column) + end +end + +# Indented code blocks parser +class MdIndentedCodeBlockParser + super MdBlockParser + + redef type BLOCK: MdIndentedCodeBlock + redef var block = new MdIndentedCodeBlock(location, use_tabs) is lazy + + # Indent is tab? + var use_tabs: Bool + + # Block content + var content = new Buffer + + redef fun try_continue(state) do + if state.indent >= 4 then + return new MdBlockContinue.at_column(state.column + 4) + else if state.is_blank then + return new MdBlockContinue.at_index(state.next_non_space_index) + end + return null + end + + redef fun add_line(line) do + if not content.is_empty then + content.add('\n') + end + content.append(line) + end + + redef fun finalize(parser) do + super + + add_line(" ") + var content = self.content.to_s + var literal = content.replace_first(re_trailing_blank_lines, "\n") + block.literal = literal + + var lines = literal.split("\n") + location.line_end = location.line_start + lines.length - 2 + location.column_end = content_offset + lines[lines.length - 2].length + 4 + end +end + +# Indented code blocks parser factory +class MdIndentedCodeBlockParserFactory + super MdBlockParserFactory + + redef fun try_start(state, matched_block_parser) do + if state.indent < 4 then return null + if state.is_blank then return null + if state.active_block_parser.block isa MdParagraph then return null + + var use_tabs = state.line_string.has_prefix("\t") + return (new MdBlockStart( + [new MdIndentedCodeBlockParser( + state.line, + state.column + 1, + state.column, + use_tabs)]) + ).at_column(state.column + 4) + end +end + +# Fenced code blocks parser +class MdFencedCodeBlockParser + super MdBlockParser + + redef type BLOCK: MdFencedCodeBlock + redef var block = new MdFencedCodeBlock(location, fence_char, fence_length, fence_indent) is lazy + + # Fence character + var fence_char: Char + + # Fence length + var fence_length: Int + + # Fence indent + var fence_indent: Int + + # Fence first line + var first_line: nullable String = null + + # Fence other lines + var other_lines = new Buffer + + redef fun try_continue(state) do + var next_non_space = state.next_non_space_index + var new_index = state.index + var line = state.line_string + + if state.indent <= 3 and next_non_space < line.length and + line.chars[next_non_space] == fence_char then + + var match = line.substring(next_non_space, line.length - next_non_space). + search(re_closing_fence) + if match != null and match.subs[0].as(not null).length >= fence_length then + # closing fence - we're at end of line, so we can finalize now + return new MdBlockContinue.finished + end + end + + # skip optional spaces of fence indent + var i = fence_indent + while i > 0 and new_index < line.length and line.chars[new_index] == ' ' do + new_index += 1 + i -= 1 + end + + return new MdBlockContinue.at_index(new_index) + end + + redef fun add_line(line) do + if first_line == null then + first_line = line + else + other_lines.append(line) + other_lines.add '\n' + end + end + + redef fun finalize(parser) do + super + + # first line become info string + var first_line = self.first_line + if first_line != null then + var info = first_line.trim.unescape_string + if not info.is_empty then block.info = info + end + + var content = other_lines.to_s + block.literal = content + + var lines = content.split("\n") + location.line_end = location.line_start + lines.length + location.column_end = content_offset + fence_indent + fence_length + end +end + +# Fenced code blocks parser factory +class MdFencedCodeBlockParserFactory + super MdBlockQuoteParserFactory + + redef fun try_start(state, matched_block_parser) do + var next_non_space = state.next_non_space_index + var line = state.line_string + + if state.indent >= 4 then return null + + var match = line.substring(next_non_space, line.length - next_non_space).search(re_opening_fence) + if match == null then return null + + var fence_length + var fence_char + var sub0 = match.subs[0] + if sub0 != null then + fence_length = sub0.length + fence_char = sub0.to_s.chars.first + else + fence_length = match.subs[2].as(not null).length + fence_char = match.subs[2].as(not null).to_s.chars.first + end + if fence_char == '`' and match.to_s.has("[^`]+`".to_re) then + return null + else if match.to_s.has("[^~]+~".to_re) then + return null + end + return (new MdBlockStart( + [new MdFencedCodeBlockParser( + state.line, + state.column + 1, + state.column, + fence_char, + fence_length, + state.indent)] + )).at_index(next_non_space + fence_length) + end +end + +# List blocks parser +class MdListBlockParser + super MdBlockParser + + redef type BLOCK: MdListBlock + + redef var block is lazy do + if is_ordered then + return new MdOrderedList(location, digit.as(not null), delim.as(not null)) + else + return new MdUnorderedList(location, bullet.as(not null)) + end + end + + # Is this list ordered + var is_ordered: Bool + + # List bullet if unordered + var bullet: nullable Char + + # List digit if ordered + var digit: nullable Int + + # List delimiter if ordered + var delim: nullable Char + + redef fun try_continue(state) do return new MdBlockContinue.at_index(state.index) + + redef fun finalize(parser) do + super + + var item = block.first_child + while item != null do + # check for non-final list item ending with blank line + if parser.ends_with_blank_line(item) and item.next != null then + block.is_tight = false + break + end + # recurse into children of list item to see if there are spaces between any of them + var sub_item = item.first_child + while sub_item != null do + if parser.ends_with_blank_line(sub_item) and + (item.next != null or sub_item.next != null) then + block.is_tight = false + break + end + sub_item = sub_item.next + end + item = item.next + end + end + + redef fun parse_inlines(inline_parser) do + var last_child = block.last_child + if last_child != null then + location.line_end = last_child.location.line_end + location.column_end = last_child.location.column_end + end + end +end + +# List blocks parser factory +class MdListBlockParserFactory + super MdBlockQuoteParserFactory + + redef fun try_start(state, matched_block_parser) do + if state.indent >= 4 and not matched_block_parser isa MdListBlockParser then return null + + var marker_index = state.next_non_space_index + var marker_column = state.column + state.indent + + var in_paragraph = matched_block_parser isa MdParagraphParser and matched_block_parser.content != null + var list_data = parse_list_marker(state, state.line_string, marker_index, marker_column, in_paragraph) + if list_data == null then return null + + + var new_column = list_data.content_column + var list_item_parser = new MdListItemParser( + state.line, + state.column + 1, + new_column, + new_column - state.column) + + # prepend the list block if needed + if not matched_block_parser isa MdListBlockParser or not lists_match(matched_block_parser.block, list_data) then + var list_block_parser = new MdListBlockParser(state.line, state.column + 1, new_column - state.column, list_data.is_ordered, list_data.bullet, list_data.digit, list_data.delim) + list_block_parser.block.is_tight = true + + return (new MdBlockStart([list_block_parser, list_item_parser: MdBlockParser])).at_column(new_column) + end + return (new MdBlockStart([list_item_parser])).at_column(new_column) + end + + private fun parse_list_marker(state: MdParser, line: String, marker_index, marker_column: Int, in_paragraph: Bool): nullable MdListData do + var rest = line.substring(marker_index, line.length - marker_index) + var match = rest.search(re_list_marker) + if match == null then return null + + var is_ordered + var bullet = null + var digit = null + var delim = null + + var bullet_match = match.subs[0] + if bullet_match != null then + is_ordered = false + bullet = bullet_match.to_s.chars[0] + else + is_ordered = true + digit = match.subs[2].as(not null).to_s.to_i + delim = match.subs[3].as(not null).to_s.chars[0] + end + + var marker_length = match.length + if match.to_s.has_suffix(" ") or match.to_s.has_suffix("\t") then + marker_length -= 1 + end + var index_after_marker = marker_index + marker_length + + # marker doesn't include tabs, so counting them as column directly is ok + var column_after_marker = marker_column + marker_length + # the column within the line where the content starts + var content_column = column_after_marker + + # see at which column the content starts if there is content + var has_content = false + for i in [index_after_marker .. line.length[ do + var c = line.chars[i] + if c == '\t' then + content_column += content_column.columns_to_next_tab_stop + else if c == ' ' then + content_column += 1 + else + has_content = true + break + end + end + + if in_paragraph then + # if the list item is ordered, then start number must be 1 to interrupt a paragraph + if is_ordered and digit != 1 then + return null + end + # empty list item can not interrupt a paragraph + if not has_content then + return null + end + end + + if not has_content or (content_column - column_after_marker) > 4 then + # if this line is blank or has a code block, default to 1 space after marker + content_column = column_after_marker + 1 + end + return new MdListData(is_ordered, bullet, digit, delim, content_column) + end + + # Return true if the two list items are of the same type + # + # With the same delimiter and bullet character. + # This is used in agglomerating list items into lists + private fun lists_match(a: MdListBlock, b: MdListData): Bool do + if a isa MdUnorderedList and not b.is_ordered then + return a.bullet_marker == b.bullet + else if a isa MdOrderedList and b.is_ordered then + return a.delimiter == b.delim + end + return false + end +end + +# Parsed list data +private class MdListData + + var is_ordered: Bool + + var bullet: nullable Char + + var digit: nullable Int + + var delim: nullable Char + + # Column the content start at + var content_column: Int +end + +# List items parser +class MdListItemParser + super MdBlockParser + + redef type BLOCK: MdListItem + redef var block = new MdListItem(location) is lazy + + # List item content indend + var content_indent: Int + + redef fun try_continue(state) do + if state.is_blank then + if block.first_child == null then + # blank line after empty list item + return null + end + return new MdBlockContinue.at_index(state.next_non_space_index) + end + if state.indent >= content_indent then + return new MdBlockContinue.at_column(state.column + content_indent) + end + return null + end + + redef fun parse_inlines(inline_parser) do + var last_child = block.last_child + if last_child != null then + location.line_end = last_child.location.line_end + location.column_end = last_child.location.column_end + end + end +end + +# Thematic breaks parser +class MdThematicBreakParser + super MdBlockParser + + redef type BLOCK: MdThematicBreak + redef var block = new MdThematicBreak(location, pattern) is lazy + + # Thematic break pattern + var pattern: String + + redef fun try_continue(state) do return null + + redef fun finalize(parser) do + super + + location.line_end = line_start + location.column_end = column_start + pattern.length - 1 + end +end + +# Thematic breaks parser factory +class MdThematicBreakParserFactory + super MdBlockQuoteParserFactory + + redef fun try_start(state, matched_block_parser) do + if state.indent >= 4 then return null + + var next_non_space = state.next_non_space_index + var line = state.line_string + var tbreak = line.substring(next_non_space, line.length - next_non_space).search(re_thematic_break) + if tbreak != null then + return (new MdBlockStart( + [new MdThematicBreakParser( + state.line, + state.column + 1, + next_non_space, + tbreak.to_s)] + )).at_index(line.length) + end + return null + end +end + +# Paragraphs parser +class MdParagraphParser + super MdBlockParser + + redef type BLOCK: MdParagraph + + redef var block = new MdParagraph(location) is lazy + + # Paragraph content + var content: nullable Buffer = new Buffer + + redef fun try_continue(state) do + if state.is_blank then return null + return new MdBlockContinue.at_index(state.index) + end + + redef fun add_line(line) do + var content = self.content + if content == null then return + if not content.is_empty then + content.add('\n') + end + content.append(line) + end + + redef fun finalize(parser) do + super + + var inline_parser = parser.inline_parser + var content = self.content + if content == null then return + + var content_string = content.to_s + var has_reference_defs = false + + var pos = inline_parser.parse_reference(content_string) + # try parsing the beginning as link reference definitions + while content_string.length > 3 and content_string.chars[0] == '[' and pos != 0 do + content_string = content_string.substring(pos, content_string.length - pos) + has_reference_defs = true + pos = inline_parser.parse_reference(content_string) + end + + if has_reference_defs and content_string.is_blank then + block.unlink + self.content = null + else + self.content = new Buffer.from_text(content_string) + end + end + + redef fun parse_inlines(inline_parser) do + var content = self.content + if content == null then return + inline_parser.parse(content.to_s, content_offset, block) + + var last_child = block.last_child + if last_child != null then + location.line_end = last_child.location.line_end + location.column_end = last_child.location.column_end + end + end +end + +# Html blocks parser +class MdHtmlBlockParser + super MdBlockParser + + redef type BLOCK: MdHtmlBlock + redef var block = new MdHtmlBlock(location) is lazy + + # Closing tag pattern + # + # Or null if the block is not closed + var closing_pattern: nullable Pattern + + # Is the current block finished? + var finished = false + + # Block content + var content = new Buffer + + redef fun try_continue(state) do + if finished then return null + + # blank lin ends type 6 and 7 blocks + if state.is_blank and closing_pattern == null then return null + + return new MdBlockContinue.at_index(state.index) + end + + redef fun add_line(line) do + if not content.is_empty then + content.add('\n') + end + content.append(line) + var closing_pattern = self.closing_pattern + if closing_pattern != null and line.has(closing_pattern) then + finished = true + end + end + + redef fun finalize(parser) do + super + + var content = self.content.to_s + block.literal = content + + var lines = content.split("\n") + location.line_end = location.line_start + lines.length - 1 + location.column_end = lines.last.length + end +end + +# Html blocks parser factory +class MdHtmlBlockParserFactory + super MdBlockParserFactory + + redef fun try_start(state, matched_block_parser) do + var next_non_space = state.next_non_space_index + var line = state.line_string + + if state.indent >= 4 or line.chars[next_non_space] != '<' then return null + + for block_type in [0..6] do + # type 7 can not interrupt a paragraph + if block_type == 6 and matched_block_parser.block isa MdParagraph then continue + var opener = re_html_blocks[block_type].first + var closer = re_html_blocks[block_type].last + if line.substring(next_non_space, line.length - next_non_space).has(opener.as(not null)) then + return (new MdBlockStart( + [new MdHtmlBlockParser( + state.line, + state.column + 1, + next_non_space, + closer)]) + ).at_index(state.index) + end + end + return null + end +end + +# Post Processing + +# Markdown post processor +# +# A Markdown AST visitor called after parsing from a MdParser +abstract class MdPostProcessor + super MdVisitor + + # Document behing processed + # + # Availlable only during a call to `post_process`. + var document: nullable MdDocument = null + + # Post process the `document` parsed by `parser` + fun post_process(parser: MdParser, document: MdDocument) do + self.document = document + enter_visit(document) + self.document = null + end + + # Call `MdNode::post_process` + redef fun visit(node) do node.post_process(self) +end + +redef class MdNode + + # Accept the visit of a `MdPostProcessor` + fun post_process(v: MdPostProcessor) do visit_all(v) +end + +# Utils + +redef class Sys + # ATX headings matching + private var re_atx_heading: Regex = "^(#\{1,6\})([ \t]+|$)".to_re + + # ATX trailings matching + private var re_atx_trailing: Regex = "(^|[ \t]+)#+[ \t]*$".to_re + + # SeText headings matching + private var re_setext_heading: Regex = "^(=+|-+)[ \t]*$".to_re + + # Blank lines matching + var re_trailing_blank_lines: Regex = "(\n[ \t]*)+$".to_re + + # Opening fence matching + var re_opening_fence: Regex = "^(`\{3,\})(.*)|^(~\{3,\})(.*)".to_re + + # Closing fence matching + var re_closing_fence: Regex = "^(`\{3,\}|~\{3,\})( *$)".to_re + + # List marker matching + var re_list_marker: Regex = "^([*+-])( |\t|$)|^([0-9]\{1,9\})([.)])( |\t|$)".to_re + + # Thematic break pattern + var re_thematic_break: Regex = "^((\\*[ \t]*)\{3,\}|(_[ \t]*)\{3,\}|(-[ \t]*)\{3,\})[ \t]*$".to_re + + # HTML blocks patterns + var re_html_blocks: Array[Array[nullable Regex]] do + var blocks = new Array[Array[nullable Regex]] + + var re0_opening = "^<(script|pre|style)(\\s|>|$)".to_re + re0_opening.ignore_case = true + var re0_closing = "".to_re + re0_closing.ignore_case = true + blocks.add([re0_opening, re0_closing]) + + blocks.add([ + "^".to_re + ]) + + blocks.add([ + "^<[?]".to_re, + "\\?>".to_re + ]) + + blocks.add([ + "^".to_re + ]) + + blocks.add([ + "^".to_re + ]) + + var re5_opening = "^]|$)".to_re + re5_opening.ignore_case = true + blocks.add([re5_opening, null]) + + var p_tagname = "[A-Za-z][A-Za-z0-9-]*" + var p_attribute_name = "[a-zA-Z_:][a-zA-Z0-9:._-]*" + var p_uquoted_value = "[^\"'=<>`\\x00-\\x20]+" + var p_squoted_value = "'[^']*'" + var p_dquoted_value = "\"[^\"]*\"" + var p_attribute_value = "({p_uquoted_value}|{p_squoted_value}|{p_dquoted_value})" + var p_attribute_value_spec = "(\\s*=\\s*{p_attribute_value})" + var p_attribute = "(\\s{p_attribute_name}{p_attribute_value_spec}?)" + var p_opentag = "<{p_tagname}{p_attribute}*\\s*/?>" + var p_closetag = "]" + var re6_opening = "^({p_opentag}|{p_closetag})\\s*$".to_re + re6_opening.ignore_case = true + blocks.add([re6_opening, null]) + + return blocks + end +end + +redef class Int + + # Tab stop is 4 + private fun columns_to_next_tab_stop: Int do return 4 - (self % 4) +end + +redef class String + + # Is this string blank? + # + # i.e. contains only spacing characters. + private fun is_blank: Bool do + for i in [0 .. length[ do + var c = chars[i] + if c == ' ' or c == '\t' or c == '\n' or c == '\r' then + continue + else + return false + end + end + return true + end + + # Is the character at `index` a space or a tab + # + # Return false if `index > self.length`. + private fun is_space_or_tab(index: Int): Bool do + if index >= length then return false + var c = chars[index] + return c == ' ' or c == '\t' + end +end diff --git a/lib/markdown2/markdown_github.nit b/lib/markdown2/markdown_github.nit new file mode 100644 index 0000000..2239953 --- /dev/null +++ b/lib/markdown2/markdown_github.nit @@ -0,0 +1,117 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Markdown Github mode +# +# Enables: +# * strike processing: ~strike~ +# * super processing: ^super^ +# +# TODO table +# TODO todo lists +module markdown_github + +intrude import markdown_inline_parsing +intrude import markdown_block_parsing + +redef class MdParser + + # Enable Github mode + var github_mode = false is writable + + redef var inline_parser is lazy do + var parser = super + parser.github_mode = github_mode + return parser + end +end + +redef class MdInlineParser + + # Enable Github mode + private var github_mode = false + + redef var delimiter_processors is lazy do + var delimiters = super + if github_mode then + delimiters.add new MdStrikeProcessor + delimiters.add new MdSuperProcessor + end + return delimiters + end +end + +# Strike processor +class MdStrikeProcessor + super MdEmphasisDelimiterProcessor + noautoinit + + redef var delimiter_char = '~' + redef var min_length = 1 + redef fun delimiter_use(opener, closer) do return opener.original_length + + redef fun process(opener, closer, delimiter_use) do + var node = new MdStrike( + new MdLocation( + opener.location.line_start, + opener.location.column_start, + closer.location.line_end, + closer.location.column_end), + opening_delimiter.to_s * delimiter_use) + var tmp = opener.next + while tmp != null and tmp != closer do + var next = tmp.next + node.append_child(tmp) + tmp = next + end + opener.insert_after(node) + end +end + +# Striked text +class MdStrike + super MdDelimited +end + +# Super processor +class MdSuperProcessor + super MdEmphasisDelimiterProcessor + noautoinit + + redef var delimiter_char = '^' + redef var min_length = 1 + redef fun delimiter_use(opener, closer) do return opener.original_length + + redef fun process(opener, closer, delimiter_use) do + var node = new MdSuper( + new MdLocation( + opener.location.line_start, + opener.location.column_start, + closer.location.line_end, + closer.location.column_end), + opening_delimiter.to_s * delimiter_use) + var tmp = opener.next + while tmp != null and tmp != closer do + var next = tmp.next + node.append_child(tmp) + tmp = next + end + opener.insert_after(node) + end +end + +# Super text +class MdSuper + super MdDelimited +end diff --git a/lib/markdown2/markdown_html_rendering.nit b/lib/markdown2/markdown_html_rendering.nit new file mode 100644 index 0000000..11addf6 --- /dev/null +++ b/lib/markdown2/markdown_html_rendering.nit @@ -0,0 +1,458 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# HTML rendering of Markdown documents +module markdown_html_rendering + +import markdown_rendering +import markdown_github +import markdown_wikilinks + +# Markdown document renderer to HTML +class HtmlRenderer + super MdRenderer + + # HTML output under construction + private var html: Buffer is noinit + + # Render `document` as HTML + redef fun render(document) do + reset + enter_visit(document) + return html.write_to_string + end + + redef fun visit(node) do node.render_html(self) + + # Reset `headings` and internal state + fun reset do + html = new Buffer + if enable_heading_ids then headings.clear + end + + # Last char visited + # + # Used to avoid double blank lines. + private var last_char: nullable Char = null + + # Add `string` to `html` + private fun add(string: String) do + html.append(string) + if not html.is_empty then + last_char = html.last + end + end + + # Add a raw `html` string to the output + # + # Raw means that the string will not be escaped. + fun add_raw(html: String) do add html + + # Add `text` string to the output + # + # The string will be escaped. + fun add_text(text: String) do add html_escape(text, true) + + # Add a blank line to the output + fun add_line do + if last_char != null and last_char != '\n' then + add "\n" + end + end + + # Escape `string` to HTML + # + # When `keep_entities`, HTML entities will not be escaped. + fun html_escape(string: String, keep_entities: Bool): String do + var buf: nullable Buffer = null + for i in [0..string.length[ do + var c = string.chars[i] + var sub = null + if c == '&' and (not keep_entities or string.search_from(re_entity, i) == null) then + sub = "&" + else if c == '<' then + sub = "<" + else if c == '>' then + sub = ">" + else if c == '"' then + sub = """ + else + if buf != null then buf.add c + continue + end + if buf == null then + buf = new Buffer + for j in [0..i[ do buf.add string.chars[j] + end + buf.append sub + end + + if buf == null then return string + return buf.to_s + end + + # HTML entity pattern + private var re_entity: Regex = "^&(#x[a-f0-9]\{1,8\}|#[0-9]\{1,8\}|[a-z][a-z0-9]\{1,31\});".to_re + + # Encode the `uri` string + fun encode_uri(uri: String): String do + var buf = new Buffer + + var i = 0 + while i < uri.length do + var c = uri.chars[i] + if (c >= '0' and c <= '9') or + (c >= 'a' and c <= 'z') or + (c >= 'A' and c <= 'Z') or + c == ';' or c == ',' or c == '/' or c == '?' or + c == ':' or c == '@' or c == '=' or c == '+' or + c == '$' or c == '-' or c == '_' or c == '.' or + c == '!' or c == '~' or c == '*' or c == '(' or + c == ')' or c == '#' or c == '\'' + then + buf.add c + else if c == '&' then + buf.append "&" + else if c == '%' and uri.search_from(re_uri_code, i) != null then + buf.append uri.substring(i, 3) + i += 2 + else + var bytes = c.to_s.bytes + for b in bytes do buf.append "%{b.to_i.to_hex}".to_upper + end + i += 1 + end + + return buf.to_s + end + + # URI encode pattern + private var re_uri_code: Regex = "^%[a-zA-Z0-9]\{2\}".to_re + + # Add `id` tags to headings + var enable_heading_ids = false is optional, writable + + # Associate headings ids to blocks + var headings = new ArrayMap[String, MdHeading] + + # Strip heading id + fun strip_id(text: String): String do + # strip id + var b = new FlatBuffer + for c in text do + if c == ' ' then + b.add '_' + else + if not c.is_letter and + not c.is_digit and + not allowed_id_chars.has(c) then continue + b.add c + end + end + var res = b.to_s + if res.is_empty then res = "_" + var key = res + # check for multiple id definitions + if headings.has_key(key) then + var i = 1 + key = "{res}_{i}" + while headings.has_key(key) do + i += 1 + key = "{res}_{i}" + end + end + return key + end + + # Allowed characters in ids + var allowed_id_chars: Array[Char] = ['-', '_', ':', '.'] +end + +redef class MdNode + + # Render `self` as HTML + fun render_html(v: HtmlRenderer) do visit_all(v) +end + +# Blocks + +redef class MdBlockQuote + redef fun render_html(v) do + v.add_line + v.add_raw "
" + v.add_line + visit_all(v) + v.add_line + v.add_raw "
" + v.add_line + end +end + +redef class MdCodeBlock + redef fun render_html(v) do + var info = self.info + v.add_line + v.add_raw "
"
+		v.add_raw ""
+		var literal = self.literal or else ""
+		var lines = literal.split("\n")
+		for i in [0..lines.length[ do
+			var line = lines[i]
+			v.add_raw v.html_escape(line, false)
+			if i < lines.length - 1 then
+				v.add_raw "\n"
+			end
+		end
+		v.add_raw ""
+		v.add_raw "
" + v.add_line + end +end + +redef class MdHeading + redef fun render_html(v) do + v.add_line + if v.enable_heading_ids then + var id = self.id + if id == null then + id = v.strip_id(title) + v.headings[id] = self + self.id = id + end + v.add_raw "" + else + v.add_raw "" + end + visit_all(v) + v.add_raw "" + v.add_line + end + + # + var id: nullable String = null + + # + fun title: String do + var v = new RawTextVisitor + return v.render(self) + end +end + +redef class MdUnorderedList + redef fun render_html(v) do + v.add_line + v.add_raw "
    " + v.add_line + visit_all(v) + v.add_line + v.add_raw "
" + v.add_line + end +end + +redef class MdOrderedList + redef fun render_html(v) do + var start = self.start_number + v.add_line + v.add_raw "" + v.add_line + visit_all(v) + v.add_line + v.add_raw "" + v.add_line + end +end + +redef class MdListItem + redef fun render_html(v) do + v.add_raw "
  • " + visit_all(v) + v.add_raw "
  • " + v.add_line + end +end + +redef class MdParagraph + redef fun render_html(v) do + var is_tight = is_in_tight_list + if not is_tight then + v.add_line + v.add_raw "

    " + end + visit_all(v) + if not is_tight then + v.add_raw "

    " + v.add_line + end + end +end + +redef class MdThematicBreak + redef fun render_html(v) do + v.add_line + v.add_raw "
    " + v.add_line + end +end + +redef class MdHtmlBlock + redef fun render_html(v) do + v.add_line + var literal = self.literal or else "" + var lines = literal.split("\n") + for i in [0..lines.length[ do + var line = lines[i] + if not line.trim.is_empty then + v.add_raw line + end + if i < lines.length - 1 then + v.add_raw "\n" + end + end + v.add_line + end +end + +# Inlines + +redef class MdHardLineBreak + redef fun render_html(v) do + v.add_raw "
    " + v.add_line + end +end + +redef class MdSoftLineBreak + redef fun render_html(v) do + v.add_raw "\n" + end +end + +redef class MdCode + redef fun render_html(v) do + v.add_raw "" + v.add_raw v.html_escape(literal, false) + v.add_raw "" + end +end + +redef class MdEmphasis + redef fun render_html(v) do + v.add_raw "" + visit_all(v) + v.add_raw "" + end +end + +redef class MdStrongEmphasis + redef fun render_html(v) do + v.add_raw "" + visit_all(v) + v.add_raw "" + end +end + +redef class MdHtmlInline + redef fun render_html(v) do + v.add_raw literal + end +end + +redef class MdImage + redef fun render_html(v) do + var url = self.destination + var title = self.title + v.add_raw "" + end + + private fun alt_text: String do + var v = new RawTextVisitor + return v.render(self) + end +end + +redef class MdLink + redef fun render_html(v) do + var url = self.destination + var title = self.title + v.add_raw "" + visit_all(v) + v.add_raw "" + end +end + +redef class MdText + redef fun render_html(v) do + v.add_text literal + end +end + +# Github mode + +redef class MdStrike + redef fun render_html(v) do + v.add_raw "" + visit_all(v) + v.add_raw "" + end +end + +redef class MdSuper + redef fun render_html(v) do + v.add_raw "" + visit_all(v) + v.add_raw "" + end +end + +# Wikilinks mode + +redef class MdWikilink + + # Dummy rendering of wikilinks + # + # Clients should redefine this. + redef fun render_html(v) do + v.add_raw "" + visit_all(v) + v.add_raw "" + end +end diff --git a/lib/markdown2/markdown_inline_parsing.nit b/lib/markdown2/markdown_inline_parsing.nit new file mode 100644 index 0000000..703f46e --- /dev/null +++ b/lib/markdown2/markdown_inline_parsing.nit @@ -0,0 +1,1401 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Parser for inline markdown +# +# Used to create the AST representation of inline nodes like emphasis, code, links +# images etc. +module markdown_inline_parsing + +import markdown_ast + +# Parser for inline content (text, links, emphasis, etc) +class MdInlineParser + + # List of delimiter processors to use + private var delimiter_processors: Array[MdDelimiterProcessor] is lazy do + var delimiters = new Array[MdDelimiterProcessor] + delimiters.add new MdAsteriskDelimiterProcessor + delimiters.add new MdUnderscoreDelimiterProcessor + return delimiters + end + + # Map special characters to their delimiter processor + private var delimiter_processors_map: Map[Char, MdDelimiterProcessor] is lazy do + var map = new HashMap[Char, MdDelimiterProcessor] + for delimiter_processor in delimiter_processors do + add_delimiter_processor(delimiter_processor, map) + end + special_characters.add_all map.keys + return map + end + + # Register a delimiter processor + private fun add_delimiter_processor(delimiter_processor: MdDelimiterProcessor, map: Map[Char, MdDelimiterProcessor]) do + var opening = delimiter_processor.opening_delimiter + var closing = delimiter_processor.closing_delimiter + if opening == closing then + if map.has_key(opening) then + var old = map[opening] + if old.opening_delimiter == old.closing_delimiter then + var s: MdStaggeredDelimiterProcessor + if old isa MdStaggeredDelimiterProcessor then + s = old + else + s = new MdStaggeredDelimiterProcessor(opening) + s.add old + end + s.add delimiter_processor + map[opening] = s + else + add_delimiter_processor_for_char(opening, delimiter_processor, map) + end + else + add_delimiter_processor_for_char(opening, delimiter_processor, map) + end + else + add_delimiter_processor_for_char(opening, delimiter_processor, map) + add_delimiter_processor_for_char(closing, delimiter_processor, map) + end + end + + # Register a delimiter processor for a special character + private fun add_delimiter_processor_for_char(delimiter_char: Char, delimiter_processor: MdDelimiterProcessor, map: Map[Char, MdDelimiterProcessor]) do + assert not map.has_key(delimiter_char) else + print "Delimiter processor conflict with delimiter char `{delimiter_char}`" + end + map[delimiter_char] = delimiter_processor + end + + # List of characters that have a special Markdown meaning + private var special_characters: Array[Char] = ['\n', '`', '[', ']', '\\', '!', '<', '&'] + + # Link references by ID, needs to be built up using `parse_reference` before calling `parse` + private var reference_map = new HashMap[String, MdLink] + + # Current block under parsing + private var block: MdNode is noinit + + # Current input string + private var input: String is noinit + + # Current index + private var index: Int is noinit + + # Current line + private var line: Int is noinit + + # Current column + private var column: Int is noinit + + # Current column offset + private var column_offset: Int is noinit + + # Top delimiter (emphasis, strong emphasis or custom emphasis) + # Brackets are on a separate stack, different from the algorithm described in the spec. + private var last_delimiter: nullable MdDelimiter = null + + # Top opening bracket (`[` or `![`) + private var last_bracket: nullable MdBracket = null + + # Parse `input` as inline and add resulting nodes as children to `block` + fun parse(input: String, offset: Int, block: MdNode) do + self.block = block + self.input = input.trim + self.index = 0 + self.last_delimiter = null + self.last_bracket = null + self.line = block.location.line_start + self.column_offset = offset + self.column = 1 + column_offset + + var more_to_parse = parse_inline + while more_to_parse do + more_to_parse = parse_inline + end + + process_delimiters(null) + merge_child_text_nodes(block) + end + + # Advance the current index of `count` characters + private fun advance(count: Int) do + index += count + column += count + end + + # Attempt to parse a link reference + # + # Return how many characters were parsed as a reference. + # Returns 0 if none. + fun parse_reference(input: String): Int do + self.input = input + self.index = 0 + self.column = 0 + var dest + var title + var match_chars + var start_index = index + + # label + match_chars = parse_link_label + if match_chars == 0 then return 0 + advance match_chars + + var raw_label = input.substring(0, match_chars) + + # colon + if peek != ':' then return 0 + advance 1 + + # link url + spnl + + dest = parse_link_destination.first + if dest == null or dest.is_empty then return 0 + + var before_title = index + var before_column = column + spnl + title = parse_link_title + if title == null then + # rewind before spaces + index = before_title + column = before_column + end + + var at_line_end = true + if index != input.length and match(re_line_end) == null then + if title == null then + at_line_end = false + else + # the potential title we found is not at the line end, + # but it could still be a legal link reference if we discard the title + title = null + # rewind before spaces + index = before_title + column = before_column + # and instead check if the link URL is at the line end + at_line_end = match(re_line_end) != null + end + end + + if not at_line_end then return 0 + + var normalized_label = raw_label.normalize_reference + if normalized_label.is_empty then return 0 + + if not reference_map.has_key(normalized_label) then + var link = new MdLink(new MdLocation(0, 0, 0, 0), dest, title) + reference_map[normalized_label] = link + end + + return index - start_index + end + + # Line end pattern + private var re_line_end: Regex = "^ *(\n|$)".to_re + + # Append standard text to the current block + # + # Read `text` between `begin_index` and `end_index`. + private fun append_text(text: String, begin_index, end_index: nullable Int): MdText do + var node: MdText + if begin_index != null and end_index != null then + var nb_chars = end_index - begin_index + var string = text.substring(begin_index, nb_chars) + node = new MdText( + new MdLocation( + line, + column, + line, + column + nb_chars - 1 + ), string) + else + node = new MdText( + new MdLocation( + line, + column, + line, + column + text.length + ), text) + end + append_node(node) + return node + end + + # Append `node` to the current block + private fun append_node(node: MdNode) do block.append_child(node) + + # Parse the next inline element in subject, advancing input index + # + # On success, add the result to block's children and return true. + # On failure, return false. + private fun parse_inline: Bool do + var res: Bool + var c = peek + if c == '\0' then return false + if c == '\n' then + res = parse_newline + else if c == '\\' then + res = parse_backslash + else if c == '`' then + res = parse_backticks + else if c == '[' then + res = parse_open_bracket + else if c == '!' then + res = parse_bang + else if c == ']' then + res = parse_close_bracket + else if c == '<' then + res = parse_auto_link or parse_html_inline + else if c == '&' then + res = parse_entity + else + if delimiter_processors_map.has_key(c) then + res = parse_delimiters(delimiter_processors_map[c], c) + else + res = parse_string + end + end + + if not res then + advance 1 + # When we get here, it's only for a single special character that turned + # out to not have a special meaning. + # So we shouldn't have a single surrogate here, hence it should be ok + # to turn it into a String + var literal = c.to_s + append_text(literal) + end + + return true + end + + # If `re` matches at current index in the input, advance index and return the match + # Else return null. + private fun match(re: Pattern): nullable String do + if index >= input.length then return null + var match = input.search_from(re, index) + if match != null then + index = match.after + column = match.after + return match.to_s + end + return null + end + + # Return the char at the current input index, or `\0` + private fun peek: Char do + if index < input.length then + return input.chars[index] + end + return '\0' + end + + # Return the char at the current input index + 1, or `\0` + private fun peek_next: Char do + if index + 1 < input.length then + return input.chars[index + 1] + end + return '\0' + end + + # Parse zero or more space characters, incuding at most one newline + private fun spnl: Bool do + var found_nl = false + loop + var c = peek + if c == ' ' or c == '\t' then + advance 1 + continue + else if c == '\n' then + if found_nl then break + found_nl = true + advance 1 + continue + end + break + end + return true + end + + # Parse a new line + # + # If it was preceded by two spaces, return a hard line break, + # otherwise a soft line break + private fun parse_newline: Bool do + advance 1 # assume we're at a `\n` + + var last_child = block.last_child + + # check previous text for trailing spaces + # the `has_suffix` is an optimization to avoid an RE match in the common case + if last_child != null and last_child isa MdText and + (last_child.literal.has_suffix(" ")) then + var text = last_child + var literal = text.literal + var match = literal.search(re_final_space) + var spaces = if match != null then match.length else 0 + if spaces > 0 then + text.literal = literal.substring(0, literal.length - spaces) + end + last_child.location.column_end = last_child.location.column_end - spaces + if spaces >= 2 then + append_node(new MdHardLineBreak(new MdLocation(line, column - spaces - 1, line, column - 1), false)) + else + append_node(new MdSoftLineBreak(new MdLocation(line, column - spaces - 1, line, column -1))) + end + else + append_node(new MdSoftLineBreak(new MdLocation(line, column - 1, line, column - 1))) + end + line += 1 + column = 1 + column_offset + + # gobble leading spaces in next line + while peek == ' ' do + advance 1 + end + return true + end + + # Final white spaces pattern + private var re_final_space: Regex = " *$".to_re + + # Parse a backslash-escaped special character + # + # Add either the escaped characters, a hard line break (if the backslash is followed by + # a new line), or a literal backslash to the block's children. + private fun parse_backslash: Bool do + advance 1 + if peek == '\n' then + append_node(new MdHardLineBreak(new MdLocation(line, column - 1, line, column), true)) + advance 1 + line += 1 + column = 1 + column_offset + else if index < input.length and input.substring(index, 1).has(re_escapable) then + append_text(input, index, index + 1) + advance 1 + else + append_text("\\") + end + return true + end + + # Escapable characters pattern + private var p_escapable = "[]!\"#$%&\'()*+,./:;<=>?@\\[\\\\^_`\\\{|\\\}~-]" + + # Escapable characters regex + private var re_escapable: Regex = "^{p_escapable}".to_re + + # Attempt to parse backticks + # + # Adding either a backtick code span or a literal sequence of backticks. + private fun parse_backticks: Bool do + var column_before = column + var ticks = match(re_ticks_here) + if ticks == null then return false + + var after_open_ticks = index + var matched = match(re_ticks) + while matched != null do + if matched == ticks then + var content = input.substring(after_open_ticks, index - after_open_ticks - ticks.length) + content = content.trim + content = content.replace(re_whitespace, " ") + var node = new MdCode(new MdLocation(line, column_before, line, column), matched.to_s, content.trim) + append_node(node) + column += 1 + return true + end + matched = match(re_ticks) + end + # If we got here, we didn't match a closing backtick sequence + index = after_open_ticks + column = after_open_ticks + 1 + append_text(ticks) + return true + end + + # Backticks starting pattern + private var re_ticks_here: Regex = "^`+".to_re + + # Backticks pattern + private var re_ticks: Regex = "`+".to_re + + # Attempt to parse delimiters like emphasis, strong emphasis or custom delimiters + private fun parse_delimiters(delimiter_processor: MdDelimiterProcessor, delimiter_char: Char): Bool do + var res = scan_delimiters(delimiter_processor, delimiter_char) + if res == null then return false + + var length = res.count + var start_index = index + var start_column = column + + advance length + var column_before = column + column = start_column + var node = append_text(input, start_index, index) + column = column_before + + # Add entry to stack for this opener + var last_delimiter = new MdDelimiter(node, delimiter_char, res.can_open, res.can_close, last_delimiter) + last_delimiter.length = length + last_delimiter.original_length = length + + var prev = last_delimiter.prev + if prev != null then + prev.next = last_delimiter + end + self.last_delimiter = last_delimiter + return true + end + + # Add open bracket to delimiter stack and add a text node to block's children + private fun parse_open_bracket: Bool do + var start_index = index + advance 1 + + var node = append_text("[") + + # Add entry to stack for this opener + add_bracket(new MdBracket.link(node, start_index, column - 1, last_bracket, last_delimiter)) + return true + end + + # If next character is `[`, add `!` delimiter to delimiter stack and add a text node to + # block's children. + # Otherwise just add a text node. + private fun parse_bang: Bool do + var start_index = index + advance 1 + + if peek == '[' then + advance 1 + var node = append_text("![") + + # Add entry to stack for this opener + add_bracket(new MdBracket.image(node, start_index + 1, column - 2, last_bracket, last_delimiter)) + else + append_text("!") + end + return true + end + + # Try match close bracket against an opening delimiter stack + # + # Add either a link or image, or a plan `[` character, to block's children. + # If there is a matching delimiter, remove it from the delimiter stack. + private fun parse_close_bracket: Bool do + advance 1 + var start_index = index + var start_column = column + + # Get previous `[` or `![` + var opener = last_bracket + if opener == null then + # no matching opener, just return a literal + append_text("]") + return true + end + + if not opener.allowed then + # matching opener but it's not allowed, juste return a literal + append_text("]") + remove_last_bracket + return true + end + + # check to see if we have a link or image + var dest: nullable Couple[nullable String, Bool] = null + var title = null + var is_link_or_image = false + + # maybe an inline link like `[foo](\uri "title")` + if peek == '(' then + advance 1 + spnl + dest = parse_link_destination + if dest.first != null then + spnl + # title needs a whitespace before + if input.substring(index - 1, 1).has(re_whitespace) then + title = parse_link_title + spnl + end + if peek == ')' then + advance 1 + is_link_or_image = true + else + index = start_index + column = start_column + end + end + end + + # maybe a reference link like `[foo][bar]`, `[foo][]` or `[foo]` + if not is_link_or_image then + # see if there's a link label like `[bar]` or `[]` + var before_label = index + var label_length = parse_link_label + advance label_length + var ref = null + if label_length > 2 then + ref = input.substring(before_label, label_length) + else if not opener.bracket_after then + # If the second label is empty `[foo][]` or missing `[foo]`, then the first label + # is the reference. + # But it can only be a reference when there's no (unescaped) bracket in it. + # If there is, we don't even need to try to lookup the reference. + ref = input.substring(opener.index, start_index - opener.index) + end + + if ref != null then + var nref = ref.normalize_reference + if reference_map.has_key(nref) then + var link = reference_map[nref] + dest = new Couple[nullable String, Bool](link.destination, false) + title = link.title + is_link_or_image = true + end + end + end + + if is_link_or_image then + # If we got here, open is a potential opener + var link_or_image: MdLinkOrImage + if opener.is_image then + link_or_image = new MdImage(new MdLocation(line, opener.column, line, column - 1), dest.as(not null).first or else "", title) + else + link_or_image = new MdLink(new MdLocation(line, opener.column, line, column - 1), dest.as(not null).first or else "", title) + end + link_or_image.has_brackets = dest.as(not null).second + + var node = opener.node.next + while node != null do + var next = node.next + link_or_image.append_child(node) + node = next + end + append_node(link_or_image) + + # Process delimiters such as emphasis inside a link/image + process_delimiters(opener.prev_delimiter) + merge_child_text_nodes(link_or_image) + # We don't need the corresponding text node anymore, we turned it into a node + opener.node.unlink + remove_last_bracket + + # Links within links are not allowed + # We found this link, so there can be no other link around it. + if not opener.is_image then + var bracket = last_bracket + while bracket != null do + if not bracket.is_image then + # disallow link opener + bracket.allowed = false + end + bracket = bracket.prev + end + end + return true + end + + if not is_link_or_image then + if parse_wikilink then return true + end + + # no link or image + append_text("]") + remove_last_bracket + index = start_index + column = start_column + return true + end + + # Whitespace pattern + private var re_whitespace: Regex = "\\s+".to_re + + # Add a bracket token on top of the `last_bracket` stack + private fun add_bracket(bracket: MdBracket) do + var last_bracket = self.last_bracket + if last_bracket != null then + last_bracket.bracket_after = true + end + self.last_bracket = bracket + end + + # Remove the last bracket on the `last_bracket` stack + private fun remove_last_bracket do + var last_bracket = self.last_bracket + if last_bracket == null then return + self.last_bracket = last_bracket.prev + end + + # Wikilink placeholder + # + # Will be defined in sub module. + private fun parse_wikilink: Bool do return false + + # Attempt to parse a link destination, returning the string or null if not match + private fun parse_link_destination: Couple[nullable String, Bool] do + var buffer = new Buffer + + var c = peek + var parens = 0 + + var has_bracket = c == '<' + if has_bracket then advance 1 + + loop + c = peek + if c == '\0' then + break # end of input + else if c == ' ' or c == '\t' or c == '\n' or c == '\r' then + break # no spaces allowed in urls + else if c == '\\' then + var next = peek_next + if escapable.has(next) then + buffer.add next + advance 2 # skip over the backslash + continue + end + else if has_bracket and c == '>' then + advance 1 + break + else if not has_bracket and c == '(' then + parens += 1 + else if not has_bracket and c == ')' then + if parens == 0 then break + parens -= 1 + else if c == '\0' then + break + end + buffer.add c + advance 1 + end + return new Couple[nullable String, Bool](buffer.to_s, has_bracket) + end + + # Attempt to parse a link title (sans quotes), returning the string or null if no match + private fun parse_link_title: nullable String do + var c = peek + if c != '\'' and c != '"' and c != '(' then + return null + end + var opener = c + + var buffer = new Buffer + loop + advance 1 + c = peek + if c == opener or (opener == '(' and c == ')') then + advance 1 + break + else if c == '\\' then + var next = peek_next + if escapable.has(next) then + buffer.add next + advance 1 + continue + end + else if c == '\0' then + return null + end + buffer.add c + end + return buffer.to_s + end + + # Escapable characters + private var escapable = "[]!\"#$%&\'()*+,./:;<=>?@\\^_`\{|\}~-" + + # Attempt to parse a link label returning number of characters parsed + private fun parse_link_label: Int do + var i = index + while i < input.length do + var c = input[i] + if i == index and c != '[' then + return 0 + else if c == '[' and i != index then + if input[i - 1] != '\\' or (i - 2 > index and input[i - 2] == '\\') then + return 0 + end + else if c == ']' then + if i > 1001 then return 0 + if input[i - 1] != '\\' or (i - 2 > index and input[i - 2] == '\\') then + return (i - index) + 1 + end + end + i += 1 + end + return 0 + end + + # Attempt to parse an autolink (URL or email in pointy brackets) + private fun parse_auto_link: Bool do + var column_before = column + var m = match(re_autolink_email) + if m != null then + var dest = m.substring(1, m.length - 2) + var node = new MdLink(new MdLocation(line, column_before, line, column), "mailto:{dest}", null, true) + node.append_child(new MdText(new MdLocation(line, column_before + 1, line, column - 1), dest)) + column += 1 + append_node(node) + return true + end + m = match(re_autolink_url) + if m != null then + var dest = m.substring(1, m.length - 2) + var node = new MdLink(new MdLocation(line, column_before, line, column), dest, null, true) + node.append_child(new MdText(new MdLocation(line, column_before + 1, line, column - 1), dest)) + column += 1 + append_node(node) + return true + end + return false + end + + # Autolink email pattern + private var re_autolink_email: Regex = "^<([a-zA-Z0-9.!#$%&'*+/=?^_`\{|\}~-]+@[a-zA-Z0-9]([a-zA-Z0-9-]\{0,61\}[a-zA-Z0-9])?(\\.[a-zA-Z0-9]([a-zA-Z0-9-]\{0,61\}[a-zA-Z0-9])?)*)>".to_re + + # Autolink url pattern + private var re_autolink_url: Regex = "^<[a-zA-Z][a-zA-Z0-9.+-]\{1,31\}:[^<> ]*>".to_re + + # Attempt to parse an inline HTML string + private fun parse_html_inline: Bool do + var column_before = column + var m = match(re_html_tag) + if m != null then + var node = new MdHtmlInline(new MdLocation(line, column_before, line, column), m) + column += 1 + append_node(node) + return true + end + return false + end + + private var p_tagname = "[A-Za-z][A-Za-z0-9-]*" + private var p_attribute_name = "[a-zA-Z_:][a-zA-Z0-9:._-]*" + private var p_uquoted_value = "[^\"'=<>` \t\n]+" + private var p_squoted_value = "'[^']*'" + private var p_dquoted_value = "\"[^\"]*\"" + private var p_attribute_value = "({p_uquoted_value}|{p_squoted_value}|{p_dquoted_value})" + private var p_attribute_value_spec = "(\\s*=\\s*{p_attribute_value})" + private var p_attribute = "(\\s{p_attribute_name}{p_attribute_value_spec}?)" + private var p_opentag = "<{p_tagname}{p_attribute}*\\s*/?>" + private var p_closetag = "]" + private var p_html_comment = "|" + private var p_processing_instruction = "[<][?].*?[?][>]" + private var p_declaration = "]*>" + private var p_cdata = "" + private var p_html_tag = "({p_opentag}|{p_closetag}|{p_html_comment}|{p_processing_instruction}|{p_declaration}|{p_cdata})" + + # HTML tag pattern + private var re_html_tag: Regex do + var re = "^{p_html_tag}".to_re + re.ignore_case = true + return re + end + + # Attempt to parse an HTML entity + private fun parse_entity: Bool do + var m = match(re_entity_here) + if m != null then + append_text(m) + return true + end + return false + end + + # HTML entity pattern + private var re_entity_here: Regex do + var re = "^&(#x[a-f0-9]\{1,8\}|#[0-9]\{1,8\}|[a-z][a-z0-9]\{1,31\});".to_re + re.ignore_case = true + return re + end + + # Parse a run of ordinary characters + # + # Or a single character with a special meaning in markdown, as a plain string. + private fun parse_string: Bool do + var begin = index + var begin_column = column + var length = input.length + while index != length do + if special_characters.has(input.chars[index]) then + break + end + advance 1 + end + if begin != index then + var column_before = column + column = begin_column + append_text(input, begin, index) + column = column_before + return true + end + return false + end + + # Scan a sequence of characters with code `delimiter_char` + # + # Return information about the number of delimiters and whether they are positioned + # such as they can open and/or close emphasis or strong emphasis. + private fun scan_delimiters(delimiter_processor: MdDelimiterProcessor, delimiter_char: Char): nullable MdDelimiterData do + var start_index = index + var start_column = column + + var delimiter_count = 0 + while peek == delimiter_char do + delimiter_count += 1 + advance 1 + end + + if delimiter_count < delimiter_processor.min_length then + index = start_index + column = start_column + return null + end + + var before = "\n" + if start_index > 0 then + before = input.substring(start_index - 1, 1) + end + + var char_after = peek + var after = "\n" + if char_after != '\0' then + after = char_after.to_s + end + + var before_is_punctuation = before.has(re_punctuation) + var before_is_whitespace = before.has(re_whitespace_char) + var after_is_punctuation = after.has(re_punctuation) + var after_is_whitespace = after.has(re_whitespace_char) + + var left_flanking = not after_is_whitespace and + (not after_is_punctuation or before_is_whitespace or before_is_punctuation) + var right_flanking = not before_is_whitespace and + (not before_is_punctuation or after_is_whitespace or after_is_punctuation) + + var can_open + var can_close + if delimiter_char == '_' then + can_open = left_flanking and (not right_flanking or before_is_punctuation) + can_close = right_flanking and (not left_flanking or after_is_punctuation) + else + can_open = left_flanking and delimiter_char == delimiter_processor.opening_delimiter + can_close = right_flanking and delimiter_char == delimiter_processor.closing_delimiter + end + + index = start_index + column = start_column + return new MdDelimiterData(delimiter_count, can_open, can_close) + end + + # Punctuation pattern + private var re_punctuation: Regex = "^[]!\"#\\$%&'()*+,.:;<=>?@^_`\{|\}~[-]".to_re + + # Whitespace character start pattern + private var re_whitespace_char: Regex = "^[  \t\r\n]".to_re + + # Process the stack of delimiters + private fun process_delimiters(stack_bottom: nullable MdDelimiter) do + var openers_bottom = new HashMap[Char, nullable MdDelimiter] + + # find first closer above stack bottom + var closer = last_delimiter + while closer != null and closer.prev != stack_bottom do + closer = closer.prev + end + # move forward, looking for closers, and handling each + while closer != null do + var delimiter_char = closer.delimiter_char + + if not closer.can_close then + closer = closer.next + continue + end + + if not delimiter_processors_map.has_key(delimiter_char) then + closer = closer.next + continue + end + + var delimiter_processor = delimiter_processors_map[delimiter_char] + var opening_delimiter_char = delimiter_processor.opening_delimiter + + # Found delimiter closer. Now look back for first matching opener + var use_delims = 0 + var opener_found = false + var potential_opener_found = false + var opener = closer.prev + + while opener != null and opener != stack_bottom and (not openers_bottom.has_key(delimiter_char) or opener != openers_bottom[delimiter_char]) do + + if opener.can_open and opener.delimiter_char == opening_delimiter_char then + potential_opener_found = true + use_delims = delimiter_processor.delimiter_use(opener, closer) + if use_delims > 0 then + opener_found = true + break + end + end + opener = opener.prev + end + + if not opener_found then + if not potential_opener_found then + # Set lower bound for future searches for openers. + # Only do this when we didn't even have a potential opener + # (one that matches the character and can open). + # If an opener was rejected because of the number of delimiters + # (e.g. because of the "multiple of 3" rule), + # we want to consider it next time because the number of delimiter + # can change as we continue processing. + openers_bottom[delimiter_char] = closer.prev + if not closer.can_open then + # We can remove a closer that can't be an opener, + # once we've seen there's no matching opener. + remove_delimiters_keep_node(closer) + end + end + closer = closer.next + continue + end + + var opener_node = opener.as(not null).node + var closer_node = closer.node + + # Remove number of used delimieters from stack and inline nodes + opener.as(not null).length -= use_delims + closer.length -= use_delims + opener_node.literal = opener_node.literal.substring(0, + opener_node.literal.length - use_delims) + closer_node.literal = closer_node.literal.substring(0, + closer_node.literal.length - use_delims) + + remove_delimiters_between(opener, closer) + # The delimieter processor can re-parent the nodes between opener and closer, + # so make sure they're contiguous already. + # Exclusive because we want to keep opener/closer themselves. + merge_text_nodes_between_exclusive(opener_node, closer_node) + delimiter_processor.process(opener_node, closer_node, use_delims) + + # Node delimieter characters left to process, so we can remove + # delimieter and the now empty node + if opener.as(not null).length == 0 then + remove_delimiters_and_node(opener) + end + + if closer.length == 0 then + var next = closer.next + remove_delimiters_and_node(closer) + closer = next + end + end + + # Remove all delimiters + while last_delimiter != null and last_delimiter != stack_bottom do + remove_delimiters_keep_node(last_delimiter) + end + end + + # Remove all delimiters between `opener` and `closer` + private fun remove_delimiters_between(opener, closer: nullable MdDelimiter) do + if opener == null or closer == null then return + + var delimiter = closer.prev + while delimiter != null and delimiter != opener do + var previous_delimiter = delimiter.prev + remove_delimiters_keep_node(delimiter) + delimiter = previous_delimiter + end + end + + # Remove the delimiter and the corresponding text node + # + # For used delimiters, e.g. `*` in `*foo*`. + private fun remove_delimiters_and_node(delim: nullable MdDelimiter) do + if delim == null then return + + var node = delim.node + node.unlink + remove_delimiter(delim) + end + + # Remove the delimiter but keep the corresponding node as text + # + # For unused delimiters such as `_` in `foo_bar`. + private fun remove_delimiters_keep_node(delim: nullable MdDelimiter) do + remove_delimiter(delim) + end + + # Remove the delimiter `delim` + private fun remove_delimiter(delim: nullable MdDelimiter) do + if delim == null then return + + var prev = delim.prev + if prev != null then + prev.next = delim.next + end + var next = delim.next + if next == null then + # top of stack + last_delimiter = prev + else + next.prev = prev + end + end + + # Merge all nodes between `from` and `to` excluding `from` and `to` + private fun merge_text_nodes_between_exclusive(from, to: nullable MdNode) do + if from == null or to == null then return + # no node between them + if from == to or from.next == to then return + merge_text_nodes_inclusive(from.next, to.prev) + end + + # Merge all child nodes of `node` into one + private fun merge_child_text_nodes(node: nullable MdNode) do + if node == null then return + # no children or just one child node, no need for merging + if node.first_child == node.last_child then return + merge_text_nodes_inclusive(node.first_child, node.last_child) + end + + # Merge all nodes between `from` and `to` including `from` and `to` + private fun merge_text_nodes_inclusive(from, to: nullable MdNode) do + var first = null + var last = null + + var node = from + while node != null do + if node isa MdText then + var text = node + if first == null then first = text + last = text + else + merge_if_needed(first, last) + first = null + last = null + end + if node == to then break + node = node.next + end + merge_if_needed(first, last) + end + + # Merge all nodes between `first` and `last` + private fun merge_if_needed(first, last: nullable MdText) do + if first != null and last != null and first != last then + var buffer = new Buffer + buffer.append(first.literal) + var node = first.next + var stop = last.next + while node != null and node != stop do + buffer.append(node.as(MdText).literal) + first.location.line_end = node.location.line_end + first.location.column_end = node.location.column_end + var unlink = node + node = node.next + unlink.unlink + end + var literal = buffer.write_to_string + first.literal = literal + end + end +end + +# Custom delimiter processor for additional delimiters besides `_` and `*` +interface MdDelimiterProcessor + + # The character that marks the beginning of a delimited node + # + # Must not clash with anu built-in special characters. + fun opening_delimiter: Char is abstract + + # The character that marks the ending of a delimited node + # + # Must not clash with anu built-in special characters. + fun closing_delimiter: Char is abstract + + # Minimum number of delimiters characters that are needed to active this + # + # Must be at least one. + fun min_length: Int is abstract + + # Determine how many (if any) of the delimiter characters should be used + # + # This allows implementations to decide how many characters to use based on the + # properties of the delimiter runs. + # + # An implementation can also return 0 when it doesn't want to allow this particular + # combination of delimiter runs. + fun delimiter_use(opener, closer: MdDelimiter): Int is abstract + + # Process the matched delimiters + # + # For example, by wrapping the nodes between `opener` and `closer` in a new node, + # or appending a new node after the opener. + # + # Note that removal of the delimiter from the delimiter nodes and unlinking + # them is done by the caller. + fun process(opener, closer: MdText, delimiter_use: Int) is abstract +end + +# A delimiter is one or more of the same delimiter character +# +# Used for paired delimiters like emphasis or strong emphasis. +class MdDelimiter + + # Node containing the delimiter + var node: MdText + + # Character used as delimiter + var delimiter_char: Char + + # Can `self` open a delimiter? + var can_open: Bool + + # Cant `self` close a delimiter? + var can_close: Bool + + # Previous delimiter found + var prev: nullable MdDelimiter + + # Next delimiter found + var next: nullable MdDelimiter + + # The number of characters in this delimiter run that are left for processing + var length = 1 + + # The number of characters originally in this delimiter run + # + # At the start of processing, this is the same as `length`. + var original_length = 1 +end + +# Opening bracket for links and images +class MdBracket + + # Node containing the bracket + var node: MdText + + # Index of the bracket in the original string + var index: Int + + # COlumn of the bracket + var column: Int + + # Is this bracket opening an image? + var is_image: Bool + + # Previous bracket + var prev: nullable MdBracket + + # Previous delimiter + var prev_delimiter: nullable MdDelimiter + + # Whether this bracket is allowed to form a link/image + var allowed = true + + # Whether there is an unescaped bracket (opening or closing) anywhere after this bracket + var bracket_after = false + + # Create a new bracket for a link + init link(node: MdText, index: Int, column: Int, prev: nullable MdBracket, prev_delimiter: nullable MdDelimiter) do + init(node, index, column, false, prev, prev_delimiter) + end + + # Create a new bracket for an image + init image(node: MdText, index: Int, column: Int, prev: nullable MdBracket, prev_delimiter: nullable MdDelimiter) do + init(node, index, column, true, prev, prev_delimiter) + end +end + +# Data about a delimiter parsing +private class MdDelimiterData + + # Number of successive delimiters found + var count: Int + + # Can this delimiter open an inline construct? + var can_open: Bool + + # Can this delimiter close an inline construct? + var can_close: Bool +end + +# An implementation of MdDelimiterProcessor that dispatches all calls to others +# +# The sub processors called bepends on the length of the delimiter run. +# All child processors must have different minimum lengths. +# A given delimiter run is dispatched to the child with the largest acceptable minimum length. +# If not child is applicable, the one with the largest minimum length is chosen. +class MdStaggeredDelimiterProcessor + super MdDelimiterProcessor + + # Delimiter character + var delim: Char + + # Sub processors to apply + var processors = new Array[MdDelimiterProcessor] + + redef var min_length = 0 + redef fun opening_delimiter do return delim + redef fun closing_delimiter do return delim + + # Add a new sub delimiter processor + fun add(dp: MdDelimiterProcessor) do + var len = dp.min_length + var i = 0 + while i < processors.length do + var p = processors[i] + assert len != p.min_length else + print "Cannot add two delimiter processor for `{delim}` " + + "and mininimum length `{len}`" + end + if len > p.min_length then + break + end + i += 1 + end + processors.insert(dp, i) + end + + # Find the corresponding processor for a length of `len` delimiter characters + fun find_processor(len: Int): MdDelimiterProcessor do + for processor in processors do + if processor.min_length <= len then return processor + end + return processors.first + end + + redef fun delimiter_use(opener, closer) do + return find_processor(opener.length).delimiter_use(opener, closer) + end + + redef fun process(opener, closer, delimiter_use) do + find_processor(delimiter_use).process(opener, closer, delimiter_use) + end +end + +# A processor for emphasis tokens +class MdEmphasisDelimiterProcessor + super MdDelimiterProcessor + + # Delimiter character + var delimiter_char: Char + + redef var min_length = 1 + redef fun opening_delimiter do return delimiter_char + redef fun closing_delimiter do return delimiter_char + + redef fun delimiter_use(opener, closer) do + # "multiple of 3" rule for internal delimiter runs + if (opener.can_close or closer.can_open) and + ((opener.original_length + closer.original_length) % 3 == 0) then + return 0 + end + # calculate actual number of delimiters used from this closer + if opener.length >= 2 and closer.length >= 2 then + return 2 + end + return 1 + end + + redef fun process(opener, closer, delimiter_use) do + var single_delimiter = opening_delimiter.to_s + var emphasis: MdNode + if delimiter_use == 1 then + emphasis = new MdEmphasis( + new MdLocation( + opener.location.line_start, + opener.location.column_start, + closer.location.line_end, + closer.location.column_end), + single_delimiter) + else + emphasis = new MdStrongEmphasis( + new MdLocation( + opener.location.line_start, + opener.location.column_start + opener.literal.length, + closer.location.line_end, + closer.location.column_end - closer.literal.length), + "{single_delimiter}{single_delimiter}") + end + var tmp = opener.next + while tmp != null and tmp != closer do + var next = tmp.next + emphasis.append_child(tmp) + tmp = next + end + opener.insert_after(emphasis) + end +end + +# Asterisk delimiters processor +class MdAsteriskDelimiterProcessor + super MdEmphasisDelimiterProcessor + noautoinit + + redef var delimiter_char = '*' +end + +# Underscore delimters processor +class MdUnderscoreDelimiterProcessor + super MdEmphasisDelimiterProcessor + noautoinit + + redef var delimiter_char = '_' +end + +# Utils + +redef class String + + # Remove escape backslash from string + fun unescape_string: String do + if not has(re_escaped) then return self + + var buffer = new Buffer + var match = search(re_escaped) + var last_end = 0 + while match != null do + buffer.append substring(last_end, match.from - last_end) + buffer.append substring(match.from + 1, 1) + last_end = match.after + match = search_from(re_escaped, last_end) + end + if last_end < length then + buffer.append substring(last_end, length - last_end) + end + return buffer.to_s + end + + # Normalize link reference names + private fun normalize_reference: String do + var stripped = self.substring(1, length - 2).trim + var lowercase = stripped.to_lower # TODO utf-8 + return lowercase.replace(re_whitespace, " ") + end +end + +redef class Sys + private var p_escapable = "[]!\"#$%&\'()*+,./:;<=>?@\\[\\\\^_`\\\{|\\\}~-]" + private var re_escaped: Regex = "\\\\{p_escapable}".to_re + private var re_whitespace: Regex = "\\s+".to_re +end diff --git a/lib/markdown2/markdown_latex_rendering.nit b/lib/markdown2/markdown_latex_rendering.nit new file mode 100644 index 0000000..b7c4abd --- /dev/null +++ b/lib/markdown2/markdown_latex_rendering.nit @@ -0,0 +1,438 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# LaTeX rendering of Markdown documents +module markdown_latex_rendering + +import markdown_rendering +import markdown_github +import markdown_wikilinks + +# Markdown document renderer to LaTeX +class LatexRenderer + super MdRenderer + + # Generate the LaTeX document wrapper + # + # The header includes: + # * document class + # * package importation + # * begin and end document directives + var wrap_document = false is optional, writable + + # LaTeX document class + # + # Default is `article`. + var document_class = "article" is optional, writable + + # LaTeX document page format + # + # Default is `letter`. + var page_format = "letter" is optional, writable + + # LaTeX font size + # + # Default is `10pt`. + var font_size = "10pt" is optional, writable + + # Use `listings` package for code blocks? + var use_listings = false is optional, writable + + # LaTeX output under construction + private var latex: Buffer is noinit + + # Render `document` as LaTeX + redef fun render(document) do + latex = new Buffer + enter_visit(document) + return latex.write_to_string + end + + redef fun visit(node) do node.render_latex(self) + + # Indentation level + var indent = 0 + + # Add a raw `string` to the output + # + # Raw means that the string will not be escaped. + fun add_raw(string: String) do latex.append string + + # Add `text` string to the output + # + # The string will be escaped. + fun add_text(text: String) do latex.append latex_escape(text) + + # Add a blank line to the output + fun add_line do + if not latex.is_empty and latex.last != '\n' then + latex.add '\n' + end + end + + # Add an indentation depending on `ident` level + fun add_indent do latex.append " " * indent + + # Escape `string` to LaTeX + fun latex_escape(string: String): String do + var buffer = new Buffer + for i in [0 .. string.length[ do + var c = string.chars[i] + if c == '>' then + buffer.append "\\textgreater" + continue + else if c == '<' then + buffer.append "\\textless" + continue + else if c == '\\' then + buffer.append "\\textbackslash" + continue + else if escaped_chars.has(c) then + buffer.add '\\' + end + buffer.add c + end + return buffer.to_s + end + + # LaTeX characters to escape + var escaped_chars = ['%', '$', '{', '}', '_', '#', '&'] +end + +redef class MdNode + + # Render `self` as HTML + fun render_latex(v: LatexRenderer) do visit_all(v) +end + +# Blocks + +redef class MdDocument + redef fun render_latex(v) do + var wrap_document = v.wrap_document + if v.wrap_document then + v.add_line + v.add_raw "\\documentclass[{v.page_format},{v.font_size}]\{{v.document_class}\}\n\n" + v.add_raw "\\usepackage[utf8]\{inputenc\}\n" + if v.use_listings then + v.add_raw "\\usepackage\{listings\}\n" + end + v.add_raw "\\usepackage\{hyperref\}\n" + v.add_raw "\\usepackage\{graphicx\}\n" + v.add_raw "\\usepackage\{ulem\}\n\n" + v.add_raw "\\begin\{document\}\n\n" + end + var node = first_child + while node != null do + v.enter_visit node + node = node.next + if node != null then v.add_raw "\n" + end + if wrap_document then + v.add_raw "\n\\end\{document\}\n" + end + end +end + +redef class MdHeading + redef fun render_latex(v) do + var level = self.level + v.add_indent + v.add_line + if level == 1 then + v.add_raw "\\section\{" + else if level == 2 then + v.add_raw "\\subsection\{" + else if level == 3 then + v.add_raw "\\subsubsection\{" + else if level == 4 then + v.add_raw "\\paragraph\{" + else if level == 5 then + v.add_raw "\\subparagraph\{" + else + # use bold for level 6 headings + v.add_raw "\\textbf\{" + end + v.add_indent + visit_all(v) + v.add_raw "\}" + v.add_line + end +end + +redef class MdBlockQuote + redef fun render_latex(v) do + v.add_line + v.add_indent + v.add_raw "\\begin\{quote\}" + v.add_line + v.indent += 2 + visit_all(v) + v.indent -= 2 + v.add_line + v.add_indent + v.add_raw "\\end\{quote\}" + v.add_line + end +end + +redef class MdIndentedCodeBlock + redef fun render_latex(v) do + var directive = if v.use_listings then "lstlisting" else "verbatim" + v.add_line + v.add_indent + v.add_raw "\\begin\{{directive}\}" + v.add_line + v.add_raw literal or else "" + v.add_line + v.add_indent + v.add_raw "\\end\{{directive}\}" + v.add_line + end +end + +redef class MdFencedCodeBlock + redef fun render_latex(v) do + var info = self.info + var lstlistings = v.use_listings + var directive = if lstlistings then "lstlisting" else "verbatim" + v.add_line + v.add_indent + v.add_raw "\\begin\{{directive}\}" + if lstlistings and info != null and not info.is_empty then + v.add_raw "[language={info}]" + end + v.add_line + v.add_raw literal or else "" + v.add_line + v.add_indent + v.add_raw "\\end\{{directive}\}" + v.add_line + end +end + +redef class MdOrderedList + redef fun render_latex(v) do + var start = self.start_number + v.add_line + v.add_indent + v.add_raw "\\begin\{enumerate\}" + v.indent += 2 + v.add_line + if start != 1 then + v.add_indent + v.add_raw "\\setcounter\{enum{nesting_level}\}\{{start}\}" + v.add_line + end + visit_all(v) + v.indent -= 2 + v.add_line + v.add_indent + v.add_raw "\\end\{enumerate\}" + v.add_line + end + + # Depth of ordered list + # + # Used to compute the `setcounter` level. + fun nesting_level: String do + var nesting = 1 + + var parent = self.parent + while parent != null do + if parent isa MdOrderedList then nesting += 1 + parent = parent.parent + end + + if nesting <= 3 then + return "i" * nesting + end + return "iv" + end +end + +redef class MdUnorderedList + redef fun render_latex(v) do + v.add_line + v.add_indent + v.add_raw "\\begin\{itemize\}" + v.add_line + v.indent += 2 + visit_all(v) + v.indent -= 2 + v.add_line + v.add_indent + v.add_raw "\\end\{itemize\}" + v.add_line + end +end + +redef class MdListItem + redef fun render_latex(v) do + v.add_indent + v.add_raw "\\item" + v.add_line + v.indent += 2 + visit_all(v) + v.indent -= 2 + v.add_line + end +end + +redef class MdThematicBreak + redef fun render_latex(v) do + v.add_line + v.add_indent + v.add_raw "\\begin\{center\}\\rule\{3in\}\{0.4pt\}\\end\{center\}" + v.add_line + end +end + +redef class MdParagraph + redef fun render_latex(v) do + v.add_indent + visit_all(v) + v.add_line + end +end + + +redef class MdHtmlBlock + redef fun render_latex(v) do + v.add_line + v.add_indent + v.add_raw "\\begin\{verbatim\}" + v.add_line + v.add_indent + v.add_raw literal or else "" + v.add_line + v.add_indent + v.add_raw "\\end\{verbatim\}" + v.add_line + end +end + +# Inlines + +redef class MdLineBreak + redef fun render_latex(v) do + v.add_line + v.add_indent + end +end + +redef class MdCode + redef fun render_latex(v) do + v.add_raw "\\texttt\{" + v.add_text literal + v.add_raw "\}" + end +end + +redef class MdEmphasis + redef fun render_latex(v) do + v.add_raw "\\textit\{" + visit_all(v) + v.add_raw "\}" + end +end + +redef class MdStrongEmphasis + redef fun render_latex(v) do + v.add_raw "\\textbf\{" + visit_all(v) + v.add_raw "\}" + end +end + +redef class MdHtmlInline + redef fun render_latex(v) do + v.add_raw "\\texttt\{" + v.add_raw v.latex_escape(literal) + v.add_raw "\}" + end +end + +redef class MdImage + redef fun render_latex(v) do + v.add_raw "\\includegraphics\{" + v.add_text destination + v.add_raw "\}" + end + + private fun alt_text: String do + var v = new RawTextVisitor + return v.render(self) + end +end + +redef class MdLink + redef fun render_latex(v) do + if is_autolink then + v.add_raw "\\url\{" + v.add_text destination + v.add_raw "\}" + return + end + var title = self.title + v.add_raw "\\href\{" + v.add_text destination + v.add_raw "\}\{" + visit_all(v) + if title != null and not title.is_empty then + v.add_raw " (" + v.add_text title + v.add_raw ")" + end + v.add_raw "\}" + end +end + +redef class MdText + redef fun render_latex(v) do + v.add_text literal + end +end + +# Github mode + +redef class MdStrike + redef fun render_latex(v) do + v.add_raw "\\sout\{" + visit_all(v) + v.add_raw "\}" + end +end + +redef class MdSuper + redef fun render_latex(v) do + v.add_raw "\\textsuperscript\{" + visit_all(v) + v.add_raw "\}" + end +end + +# Wikilinks + +redef class MdWikilink + redef fun render_latex(v) do + v.add_raw "\\texttt\{" + var title = self.title + if title != null then + v.add_text "{title} | " + end + v.add_text link + v.add_raw "\}" + end +end diff --git a/lib/markdown2/markdown_man_rendering.nit b/lib/markdown2/markdown_man_rendering.nit new file mode 100644 index 0000000..1e047d6 --- /dev/null +++ b/lib/markdown2/markdown_man_rendering.nit @@ -0,0 +1,258 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Manpages rendering of Markdown documents +module markdown_man_rendering + +import markdown_rendering +import markdown_github +import markdown_wikilinks + +# Markdown document renderer to Manpage +class ManRenderer + super MdRenderer + + # Output under construction + private var man: Buffer is noinit + + # Render `node` as Markdown + redef fun render(node) do + man = new Buffer + enter_visit(node) + return man.write_to_string + end + + redef fun visit(node) do node.render_man(self) + + # Add `string` to `man` + fun add(string: String) do + man.append(string.replace("-", "\\-")) + end + + # Add code that need to be escaped + fun add_code(code: String) do + add code.replace(" ", "\\ ") + end + + # Add a blank line to the output + fun add_line do + add "\n" + end +end + +redef class MdNode + + # Render `self` as Manpage format + fun render_man(v: ManRenderer) do visit_all(v) +end + +# Blocks + +redef class MdBlockQuote + redef fun render_man(v) do + v.add ".RS" + visit_all(v) + v.add ".RE" + v.add_line + end +end + +redef class MdCodeBlock + redef fun render_man(v) do + v.add ".RS\n.nf\n\\f[C]" + v.add_line + + var literal = self.literal + if literal != null then + var lines = literal.split("\n") + for i in [0 .. lines.length[ do + if i == lines.length - 1 then break + var line = lines[i] + v.add_code line + v.add_line + end + end + + v.add "\\f[]\n.fi\n.RE" + v.add_line + end +end + +redef class MdHeading + redef fun render_man(v) do + var level = self.level + + if level == 1 then + v.add ".SH " + else if level == 2 then + v.add ".SS " + else if level >= 3 then + # We use dictionary (titled paragraph) to simulate a 3rd level (or more) + v.add ".TP\n" + end + visit_all(v) + v.add_line + end +end + +redef class MdUnorderedList + redef fun render_man(v) do + v.add ".RS" + v.add_line + + var node = first_child + while node != null do + v.add ".IP \\[bu] 3" + v.add_line + v.enter_visit node + v.add_line + node = node.next + end + + v.add ".RE" + v.add_line + end +end + +redef class MdOrderedList + redef fun render_man(v) do + v.add ".RS" + v.add_line + + var index = start_number + var node = first_child + while node != null do + v.add ".IP \"{index}.\" 3" + v.add_line + v.enter_visit node + v.add_line + node = node.next + index += 1 + end + + v.add ".RE" + v.add_line + end +end + +redef class MdParagraph + redef fun render_man(v) do + var in_list = is_in_list + if not in_list then + v.add_line + end + visit_all(v) + if not in_list then + v.add_line + end + end +end + +redef class MdThematicBreak + redef fun render_man(v) do + v.add "***" + v.add_line + end +end + +redef class MdHtmlBlock + redef fun render_man(v) do + v.add_line + v.add literal or else "" + v.add_line + end +end + +# Inlines + +redef class MdLineBreak + redef fun render_man(v) do + v.add_line + end +end + +redef class MdCode + redef fun render_man(v) do + v.add "\\f[C]" + v.add_code literal + v.add "\\f[]" + end +end + +redef class MdEmphasis + redef fun render_man(v) do + v.add "\\f[I]" + visit_all(v) + v.add "\\f[]" + end +end + +redef class MdStrongEmphasis + redef fun render_man(v) do + v.add "\\f[B]" + visit_all(v) + v.add "\\f[]" + end +end + +redef class MdHtmlInline + redef fun render_man(v) do + v.add literal + end +end + +redef class MdLinkOrImage + redef fun render_man(v) do + var title = self.title + + visit_all(v) + v.add " (" + v.add destination + if title != null and not title.is_empty then + v.add " " + v.add title + end + v.add ")" + end +end + +redef class MdText + redef fun render_man(v) do + v.add literal + end +end + +# Github + +redef class MdStrike + redef fun render_man(v) do + v.add "[STRIKEOUT:" + visit_all(v) + v.add "]" + end +end + +# Wikilinks + +redef class MdWikilink + redef fun render_man(v) do + v.add "(" + var title = self.title + if title != null then + v.add "{title} | " + end + v.add link + v.add ")" + end +end diff --git a/lib/markdown2/markdown_md_rendering.nit b/lib/markdown2/markdown_md_rendering.nit new file mode 100644 index 0000000..eadda1b --- /dev/null +++ b/lib/markdown2/markdown_md_rendering.nit @@ -0,0 +1,392 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Markdown rendering of Markdown documents +module markdown_md_rendering + +import markdown_rendering +import markdown_github +import markdown_wikilinks + +# Markdown document renderer to Markdown +class MarkdownRenderer + super MdRenderer + + # Markdown output under construction + private var md: Buffer is noinit + + # Render `node` as Markdown + redef fun render(node) do + reset + enter_visit(node) + return md.write_to_string + end + + redef fun visit(node) do node.render_md(self) + + # Reset internal state + fun reset do + md = new Buffer + end + + # Current indentation level + private var indent = 0 + + # Are we currently in a blockquote? + var in_quote = 0 + + # Add a `md` string to the output + fun add_raw(md: String) do self.md.append(md) + + # Add a blank line to the output + fun add_line do add_raw "\n" + + # Add an indentation depending on `ident` level + fun add_indent do + add_raw " " * indent + end +end + +private class TextLengthVisitor + super MdVisitor + + var length = 0 + + redef fun visit(node) do node.process_len(self) +end + +redef class MdNode + + # Render `self` as Markdown + fun render_md(v: MarkdownRenderer) do visit_all(v) + + private fun process_len(v: TextLengthVisitor) do visit_all(v) +end + +redef class MdDocument + redef fun render_md(v) do + var node = first_child + while node != null do + v.enter_visit(node) + node = node.next + if node != null then + v.add_line + end + end + end +end + +# Blocks + +redef class MdBlockQuote + redef fun render_md(v) do + v.in_quote += 1 + var node = first_child + while node != null do + v.add_indent + v.add_raw "> " + v.enter_visit(node) + node = node.next + end + v.in_quote -= 1 + end +end + +redef class MdIndentedCodeBlock + redef fun render_md(v) do + var literal = self.literal + if literal == null then return + + var lines = literal.split("\n") + for i in [0..lines.length[ do + if i == lines.length - 1 then continue + var line = lines[i] + if line.is_empty then + v.add_raw "\n" + else + v.add_indent + if use_tabs then + v.add_raw "\t" + else + v.add_raw " " * 4 + end + v.add_raw line + v.add_line + end + end + end +end + +redef class MdFencedCodeBlock + redef fun render_md(v) do + var info = self.info + v.add_indent + v.add_raw fence_char.to_s * fence_length + v.add_raw info or else "" + for line in (literal or else "").split("\n") do + v.add_line + if not line.is_empty then + v.add_indent + end + v.add_raw line + end + v.add_indent + v.add_raw fence_char.to_s * fence_length + v.add_line + end +end + +redef class MdHeading + redef fun render_md(v) do + if is_setext then + visit_all(v) + var length_visitor = new TextLengthVisitor + length_visitor.enter_visit(self) + v.add_line + if level == 1 then + v.add_raw "=" * length_visitor.length + else + v.add_raw "-" * length_visitor.length + end + else + v.add_raw "#" * level + v.add_raw " " + visit_all(v) + if has_atx_trailing then + v.add_raw " " + v.add_raw "#" * level + end + end + v.add_line + end +end + +redef class MdOrderedList + # Children numbering + private var md_numbering: Int = start_number is lazy +end + +redef class MdListItem + redef fun render_md(v) do + var parent = self.parent + var is_tight = parent.as(MdListBlock).is_tight + + v.add_indent + if parent isa MdUnorderedList then + v.add_raw parent.bullet_marker.to_s + v.indent += 2 + else if parent isa MdOrderedList then + v.add_raw "{parent.md_numbering}{parent.delimiter.to_s}" + v.indent += 3 + end + + var node = first_child + if node != null then + v.add_raw " " + else + v.add_line + end + while node != null do + v.enter_visit(node) + node = node.next + if node != null and not is_tight then + v.add_line + end + end + + if next != null and not is_tight then + v.add_line + end + + if parent isa MdUnorderedList then + v.indent -= 2 + else if parent isa MdOrderedList then + parent.md_numbering += 1 + v.indent -= 3 + end + end +end + +redef class MdParagraph + redef fun render_md(v) do + if not parent isa MdBlockQuote and not parent isa MdListItem or prev != null then + v.add_indent + end + # if parent isa MdBlockQuote then + # v.add_raw "> " + # var node = first_child + # while node != null do + # v.enter_visit(node) + # if node isa MdSoftLineBreak or node isa MdHardLineBreak then + # v.add_raw "> " + # end + # node = node.next + # end + # v.add_line + # return + # end + visit_all(v) + v.add_line + end +end + +redef class MdThematicBreak + redef fun render_md(v) do + v.add_raw original_pattern + v.add_line + end +end + +redef class MdHtmlBlock + redef fun render_md(v) do + v.add_raw literal or else "" + v.add_line + end +end + +# Inlines + +redef class MdHardLineBreak + redef fun render_md(v) do + if has_backslash then + v.add_raw "\\" + else + v.add_raw " " + end + v.add_line + v.add_indent + v.add_raw "> " * v.in_quote + end + + redef fun process_len(v) do + super + v.length += 1 + end +end + +redef class MdSoftLineBreak + redef fun render_md(v) do + v.add_line + v.add_indent + v.add_raw "> " * v.in_quote + end + + redef fun process_len(v) do + super + v.length += 1 + end +end + +redef class MdCode + redef fun render_md(v) do + v.add_raw delimiter + v.add_raw literal + v.add_raw delimiter + end + + redef fun process_len(v) do + super + v.length += delimiter.length + end +end + +redef class MdDelimited + redef fun render_md(v) do + v.add_raw delimiter + visit_all(v) + v.add_raw delimiter + end + + redef fun process_len(v) do + super + v.length += delimiter.length * 2 + end +end + +redef class MdHtmlInline + redef fun render_md(v) do + v.add_raw literal + end + + redef fun process_len(v) do + v.length += literal.length + end +end + +redef class MdLinkOrImage + redef fun render_md(v) do + var title = self.title + v.add_raw "[" + visit_all(v) + v.add_raw "]" + v.add_raw "(" + if has_brackets then + v.add_raw "<" + end + v.add_raw destination + if has_brackets then + v.add_raw ">" + end + if title != null and not title.is_empty then + v.add_raw " \"" + v.add_raw title.replace("\"", "\\\"") + v.add_raw "\"" + end + v.add_raw ")" + end +end + + +redef class MdImage + redef fun render_md(v) do + v.add_raw "!" + super + end +end + +redef class MdLink + redef fun render_md(v) do + if is_autolink then + v.add_raw "<" + v.add_raw destination + v.add_raw ">" + return + end + super + end +end + +redef class MdText + redef fun render_md(v) do + v.add_raw literal + end + + redef fun process_len(v) do + v.length += literal.length + end +end + +# Wikilinks + +redef class MdWikilink + redef fun render_md(v) do + v.add_raw "[[" + var title = self.title + if title != null then + v.add_raw "{title} | " + end + v.add_raw link + v.add_raw "]]" + end +end diff --git a/lib/markdown2/markdown_rendering.nit b/lib/markdown2/markdown_rendering.nit new file mode 100644 index 0000000..ff49d1c --- /dev/null +++ b/lib/markdown2/markdown_rendering.nit @@ -0,0 +1,69 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Markdown document rendering +module markdown_rendering + +import markdown_ast + +# Common interface for all markdown renderer +interface MdRenderer + super MdVisitor + + # Render `node` + fun render(node: MdNode): String is abstract +end + +# A renderer that output raw text +class RawTextVisitor + super MdRenderer + + # Text under construction + private var text: Buffer is noinit + + redef fun render(node) do + text = new Buffer + enter_visit(node) + return text.to_s + end + + # Append `string` to `text` + fun add(string: String) do text.append(string) + + redef fun visit(node) do node.render_raw_text(self) +end + +redef class MdNode + + # Return `self` as raw text + fun raw_text: String do + var v = new RawTextVisitor + return v.render(self) + end + + # Render `self` as raw text + fun render_raw_text(v: RawTextVisitor) do visit_all(v) +end + +redef class MdCode + redef fun render_raw_text(v) do v.add literal +end + +redef class MdLineBreak + redef fun render_raw_text(v) do v.add "\n" +end + +redef class MdText + redef fun render_raw_text(v) do v.add literal +end diff --git a/lib/markdown2/markdown_wikilinks.nit b/lib/markdown2/markdown_wikilinks.nit new file mode 100644 index 0000000..d6cc3a0 --- /dev/null +++ b/lib/markdown2/markdown_wikilinks.nit @@ -0,0 +1,119 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Markdown wikilinks processing +# +# Enables parsing of `[[wikilinks]]` syntax. +module markdown_wikilinks + +intrude import markdown_inline_parsing +intrude import markdown_block_parsing + +redef class MdParser + + # Enable wikilinks mode + var wikilinks_mode = false is writable + + redef var inline_parser is lazy do + var parser = super + parser.wikilinks_mode = wikilinks_mode + return parser + end +end + +redef class MdInlineParser + + # Enable wikilinks mode + private var wikilinks_mode = false + + redef fun parse_wikilink do + if not wikilinks_mode then return false + + # do we have two opening bracket? + var last_bracket = self.last_bracket + if last_bracket == null then return false + var first_bracket = last_bracket.prev + if first_bracket == null then return false + + # was the first bracket an image? + if first_bracket.is_image then return false + + # do we have two closing brackets? + if index >= input.length or input.chars[index] != ']' then return false + + advance 1 # skip last bracket + var start_index = first_bracket.index + 2 + var end_index = index - 2 + + # create wikilink node + var content = input.substring(start_index, end_index - start_index) + var parts = content.split("|") + var title = if parts.length > 1 then parts.first.trim else null + var link = parts.last.trim + + var wikilink = new MdWikilink( + new MdLocation( + first_bracket.node.location.line_start, + first_bracket.node.location.column_start - 1, + line, + column - 1), + link, title) + + var node = last_bracket.node.next + var in_link = false + while node != null do + var next = node.next + if not in_link then + if node isa MdText and node.literal.has("|") then + var buf = new Buffer + for c in node.literal.chars do + if c == '|' then + in_link = true + break + end + buf.add c + end + node.literal = buf.write_to_string.r_trim + end + wikilink.append_child(node) + else + node.unlink + end + node = next + end + + append_node(wikilink) + + # Process delimiters such as emphasis inside a link/image + process_delimiters(last_bracket.prev_delimiter) + merge_child_text_nodes(wikilink) + + # remove brackets + first_bracket.node.unlink + last_bracket.node.unlink + + return true + end +end + +# A Wikilink node +class MdWikilink + super MdNode + + # Wikilink link + var link: String is writable + + # Wikilink title + var title: nullable String = null is optional, writable +end diff --git a/lib/markdown2/nitmd.nit b/lib/markdown2/nitmd.nit new file mode 100644 index 0000000..5a6970f --- /dev/null +++ b/lib/markdown2/nitmd.nit @@ -0,0 +1,73 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# A Markdown parser for Nit. +module nitmd + +import markdown_html_rendering +import markdown_md_rendering +import markdown_man_rendering +import markdown_latex_rendering + +import config + +var opt_to = new OptionString("Specify output format (html, md, man, latex)", "-t", "--to") + +var usage = new Buffer +usage.append "Usage: nitmd [-t format] [file.md]\n" +usage.append "Translate Markdown documents to other formats.\n\n" +usage.append "If no argument, read the Markdown input from `stdin`." + +var config = new Config +config.add_option(opt_to) +config.tool_description = usage.write_to_string + +config.parse_options(args) +if config.args.length > 1 then + config.usage + exit 1 +end + +var md +if config.args.is_empty then + md = sys.stdin.read_all +else + var file = config.args.first + if not file.file_exists then + print "'{file}' not found" + exit 1 + end + md = file.to_path.read_all +end + +# Parse the input +var parser = new MdParser +var node = parser.parse(md) + +var renderer: MdRenderer +var to = opt_to.value +if to == null or to == "html" then + renderer = new HtmlRenderer +else if to == "md" then + renderer = new MarkdownRenderer +else if to == "man" then + renderer = new ManRenderer +else if to == "latex" then + renderer = new LatexRenderer +else + print "Unknown output format: {to}" + exit 1 + return +end +printn renderer.render(node) diff --git a/lib/markdown2/package.ini b/lib/markdown2/package.ini new file mode 100644 index 0000000..a138d93 --- /dev/null +++ b/lib/markdown2/package.ini @@ -0,0 +1,12 @@ +[package] +name=markdown2 +tags=format,lib +maintainer=Alexandre Terrasa +license=Apache-2.0 +desc=A markdown parser for Nit +[upstream] +browse=https://github.com/nitlang/nit/tree/master/lib/markdown2/ +git=https://github.com/nitlang/nit.git +git.directory=lib/markdown2/ +homepage=http://nitlanguage.org +issues=https://github.com/nitlang/nit/issues diff --git a/lib/markdown2/tests/commonmark_gen.nit b/lib/markdown2/tests/commonmark_gen.nit new file mode 100644 index 0000000..efebd80 --- /dev/null +++ b/lib/markdown2/tests/commonmark_gen.nit @@ -0,0 +1,251 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Generate Nitunit tests from commonmark specification. +# +# See the full specification and the test cases at . +# +# Usage: +# +# ~~~sh +# commonmark_gen +# ~~~ +module commonmark_gen + +import json +import json::static +import template + +# Generate the test cases from the JSON testfile. +class TestGenerator + + # Input file in containing the tests in JSON format + var json_file: String + + # Output directory where the Nitunit files will be generated + var output_dir: String + + # Ignored tests + # + # We ignore some tests for two reasons: + # * because `nitmd` does not fully support UTF-8 + # * because somes tests are wrong + var ignored_tests: Array[Int] do + var ignored = new Array[Int] + ignored.add_all([171, 304, 305, 306, 311, 312, 313, 477, 514]) # utf-8 tests + ignored.add_all([275, 276]) # spec is wrong compared to reference implementation + return ignored + end + + # Load the tests files from the JSON input + fun load_tests: Map[String, Array[TestCase]] do + var json = json_file.to_path.read_all.parse_json + var tests = new HashMap[String, Array[TestCase]] + + for obj in json.as(JsonArray) do + if not obj isa JsonObject then continue + + var number = obj["example"].as(Int) + if ignored_tests.has(number) then continue + + var name = "test{number}" + + var section = obj["section"].as(String) + if not tests.has_key(section) then + tests[section] = new Array[TestCase] + end + + var markdown = obj["markdown"].as(String) + markdown = markdown.replace("\\", "\\\\") + markdown = markdown.replace("\n", "\\n") + markdown = markdown.replace("\t", "\\t") + + # fix missing chars in some tests + if number == 162 then + markdown = markdown.replace("my url", "my%20url") + else if number == 467 then + markdown = markdown.replace("my uri", "my%20uri") + end + + var html = obj["html"].as(String) + html = html.replace("\\", "\\\\") + html = html.replace("\n", "\\n") + html = html.replace("\t", "\\t") + + tests[section].add(new TestCase(name, markdown, html)) + end + + return tests + end + + # Generate the Nitunit test files + fun gen_tests do + var tests = load_tests + + for section, test_cases in tests do + var test_file = new TestFile("test_commonmark_{strip_module_name(section)}") + var test_class = new TestClass("TestCommonmark{strip_class_name(section)}") + test_class.test_cases.add_all test_cases + test_file.test_classes.add test_class + test_file.save(output_dir) + end + end + + # Strip module name + # + # Used to create a Nitunit module name from a CommonMark section title. + fun strip_module_name(name: String): String do + var b = new FlatBuffer + for c in name do + if c == ' ' then + b.add '_' + else + if not c.is_letter and + not c.is_digit and + not allowed_id_chars.has(c) then continue + b.add c.to_lower + end + end + return b.to_s + end + + # Strip class name + # + # Used to create a Nitunit test class name from a CommonMark section title. + fun strip_class_name(name: String): String do + var b = new FlatBuffer + var was_space = false + for c in name do + if c == ' ' then + was_space = true + else + if not c.is_letter and + not c.is_digit and + not allowed_id_chars.has(c) then continue + if was_space then + b.add c.to_upper + was_space = false + else + b.add c + end + end + end + return b.to_s + end + + private var allowed_id_chars: Array[Char] = ['-', '_', ':', '.'] +end + +# A Nitunit test file +class TestFile + + # Test module name + var test_file_name: String + + # Test classes in this module + var test_classes = new Array[TestClass] + + # Copyright header and module declaration + fun header: String do + return """ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module {{{test_file_name}}} is test + +import test_markdown +""" + end + + # Render the test module as a Nit string + fun render: String do + var tpl = new Template + tpl.add header + for test_class in test_classes do + tpl.add test_class.render + end + return tpl.write_to_string + end + + # Save the test module in `directory + fun save(directory: String) do + render.write_to_file(directory / "{test_file_name}.nit") + end +end + +# A Nitunit test class +class TestClass + + # Test class name + var test_class_name: String + + # Test cases in this test class + var test_cases = new Array[TestCase] + + # Render the test class as a Nit string + fun render: String do + var tpl = new Template + tpl.addn "\nclass {test_class_name}" + tpl.addn "\tsuper TestMarkdownHtml" + tpl.addn "\ttest" + for test_case in test_cases do + tpl.add test_case.render + end + tpl.addn "end" + return tpl.write_to_string + end +end + +# A Nitunit test case +class TestCase + + # Test method name + var test_name: String + + # Markdown input + var markdown: String + + # Expected html output + var html: String + + # Render the test case as a Nit string + fun render: String do + var tpl = new Template + tpl.addn "\n\tfun {test_name} is test do" + tpl.addn "\t\tvar md = \"\"\"{markdown}\"\"\"" + tpl.addn "\t\tvar html = \"\"\"{html}\"\"\"" + tpl.addn "\t\tassert md_to_html(md) == html" + tpl.addn "\tend" + return tpl.write_to_string + end +end + +if args.length != 2 then + print "Usage: commonmark_gen " + exit 1 +end + +var gen = new TestGenerator(args.first, args.last) +gen.gen_tests diff --git a/lib/markdown2/tests/test_commonmark_atx_headings.nit b/lib/markdown2/tests/test_commonmark_atx_headings.nit new file mode 100644 index 0000000..749ab18 --- /dev/null +++ b/lib/markdown2/tests/test_commonmark_atx_headings.nit @@ -0,0 +1,130 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module test_commonmark_atx_headings is test + +import test_markdown + +class TestCommonmarkATXHeadings + super TestMarkdownHtml + test + + fun test32 is test do + var md = """# foo\n## foo\n### foo\n#### foo\n##### foo\n###### foo\n""" + var html = """

    foo

    \n

    foo

    \n

    foo

    \n

    foo

    \n
    foo
    \n
    foo
    \n""" + assert md_to_html(md) == html + end + + fun test33 is test do + var md = """####### foo\n""" + var html = """

    ####### foo

    \n""" + assert md_to_html(md) == html + end + + fun test34 is test do + var md = """#5 bolt\n\n#hashtag\n""" + var html = """

    #5 bolt

    \n

    #hashtag

    \n""" + assert md_to_html(md) == html + end + + fun test35 is test do + var md = """\\## foo\n""" + var html = """

    ## foo

    \n""" + assert md_to_html(md) == html + end + + fun test36 is test do + var md = """# foo *bar* \\*baz\\*\n""" + var html = """

    foo bar *baz*

    \n""" + assert md_to_html(md) == html + end + + fun test37 is test do + var md = """# foo \n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test38 is test do + var md = """ ### foo\n ## foo\n # foo\n""" + var html = """

    foo

    \n

    foo

    \n

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test39 is test do + var md = """ # foo\n""" + var html = """
    # foo\n
    \n""" + assert md_to_html(md) == html + end + + fun test40 is test do + var md = """foo\n # bar\n""" + var html = """

    foo\n# bar

    \n""" + assert md_to_html(md) == html + end + + fun test41 is test do + var md = """## foo ##\n ### bar ###\n""" + var html = """

    foo

    \n

    bar

    \n""" + assert md_to_html(md) == html + end + + fun test42 is test do + var md = """# foo ##################################\n##### foo ##\n""" + var html = """

    foo

    \n
    foo
    \n""" + assert md_to_html(md) == html + end + + fun test43 is test do + var md = """### foo ### \n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test44 is test do + var md = """### foo ### b\n""" + var html = """

    foo ### b

    \n""" + assert md_to_html(md) == html + end + + fun test45 is test do + var md = """# foo#\n""" + var html = """

    foo#

    \n""" + assert md_to_html(md) == html + end + + fun test46 is test do + var md = """### foo \\###\n## foo #\\##\n# foo \\#\n""" + var html = """

    foo ###

    \n

    foo ###

    \n

    foo #

    \n""" + assert md_to_html(md) == html + end + + fun test47 is test do + var md = """****\n## foo\n****\n""" + var html = """
    \n

    foo

    \n
    \n""" + assert md_to_html(md) == html + end + + fun test48 is test do + var md = """Foo bar\n# baz\nBar foo\n""" + var html = """

    Foo bar

    \n

    baz

    \n

    Bar foo

    \n""" + assert md_to_html(md) == html + end + + fun test49 is test do + var md = """## \n#\n### ###\n""" + var html = """

    \n

    \n

    \n""" + assert md_to_html(md) == html + end +end diff --git a/lib/markdown2/tests/test_commonmark_autolinks.nit b/lib/markdown2/tests/test_commonmark_autolinks.nit new file mode 100644 index 0000000..04c718c --- /dev/null +++ b/lib/markdown2/tests/test_commonmark_autolinks.nit @@ -0,0 +1,136 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module test_commonmark_autolinks is test + +import test_markdown + +class TestCommonmarkAutolinks + super TestMarkdownHtml + test + + fun test568 is test do + var md = """\n""" + var html = """

    http://foo.bar.baz

    \n""" + assert md_to_html(md) == html + end + + fun test569 is test do + var md = """\n""" + var html = """

    http://foo.bar.baz/test?q=hello&id=22&boolean

    \n""" + assert md_to_html(md) == html + end + + fun test570 is test do + var md = """\n""" + var html = """

    irc://foo.bar:2233/baz

    \n""" + assert md_to_html(md) == html + end + + fun test571 is test do + var md = """\n""" + var html = """

    MAILTO:FOO@BAR.BAZ

    \n""" + assert md_to_html(md) == html + end + + fun test572 is test do + var md = """\n""" + var html = """

    a+b+c:d

    \n""" + assert md_to_html(md) == html + end + + fun test573 is test do + var md = """\n""" + var html = """

    made-up-scheme://foo,bar

    \n""" + assert md_to_html(md) == html + end + + fun test574 is test do + var md = """\n""" + var html = """

    http://../

    \n""" + assert md_to_html(md) == html + end + + fun test575 is test do + var md = """\n""" + var html = """

    localhost:5001/foo

    \n""" + assert md_to_html(md) == html + end + + fun test576 is test do + var md = """\n""" + var html = """

    <http://foo.bar/baz bim>

    \n""" + assert md_to_html(md) == html + end + + fun test577 is test do + var md = """\n""" + var html = """

    http://example.com/\\[\\

    \n""" + assert md_to_html(md) == html + end + + fun test578 is test do + var md = """\n""" + var html = """

    foo@bar.example.com

    \n""" + assert md_to_html(md) == html + end + + fun test579 is test do + var md = """\n""" + var html = """

    foo+special@Bar.baz-bar0.com

    \n""" + assert md_to_html(md) == html + end + + fun test580 is test do + var md = """\n""" + var html = """

    <foo+@bar.example.com>

    \n""" + assert md_to_html(md) == html + end + + fun test581 is test do + var md = """<>\n""" + var html = """

    <>

    \n""" + assert md_to_html(md) == html + end + + fun test582 is test do + var md = """< http://foo.bar >\n""" + var html = """

    < http://foo.bar >

    \n""" + assert md_to_html(md) == html + end + + fun test583 is test do + var md = """\n""" + var html = """

    <m:abc>

    \n""" + assert md_to_html(md) == html + end + + fun test584 is test do + var md = """\n""" + var html = """

    <foo.bar.baz>

    \n""" + assert md_to_html(md) == html + end + + fun test585 is test do + var md = """http://example.com\n""" + var html = """

    http://example.com

    \n""" + assert md_to_html(md) == html + end + + fun test586 is test do + var md = """foo@bar.example.com\n""" + var html = """

    foo@bar.example.com

    \n""" + assert md_to_html(md) == html + end +end diff --git a/lib/markdown2/tests/test_commonmark_backslash_escapes.nit b/lib/markdown2/tests/test_commonmark_backslash_escapes.nit new file mode 100644 index 0000000..819158e --- /dev/null +++ b/lib/markdown2/tests/test_commonmark_backslash_escapes.nit @@ -0,0 +1,100 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module test_commonmark_backslash_escapes is test + +import test_markdown + +class TestCommonmarkBackslashEscapes + super TestMarkdownHtml + test + + fun test291 is test do + var md = """\\!\\"\\#\\$\\%\\&\\'\\(\\)\\*\\+\\,\\-\\.\\/\\:\\;\\<\\=\\>\\?\\@\\[\\\\\\]\\^\\_\\`\\{\\|\\}\\~\n""" + var html = """

    !"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~

    \n""" + assert md_to_html(md) == html + end + + fun test292 is test do + var md = """\\\t\\A\\a\\ \\3\\φ\\«\n""" + var html = """

    \\\t\\A\\a\\ \\3\\φ\\«

    \n""" + assert md_to_html(md) == html + end + + fun test293 is test do + var md = """\\*not emphasized*\n\\
    not a tag\n\\[not a link](/foo)\n\\`not code`\n1\\. not a list\n\\* not a list\n\\# not a heading\n\\[foo]: /url "not a reference"\n""" + var html = """

    *not emphasized*\n<br/> not a tag\n[not a link](/foo)\n`not code`\n1. not a list\n* not a list\n# not a heading\n[foo]: /url "not a reference"

    \n""" + assert md_to_html(md) == html + end + + fun test294 is test do + var md = """\\\\*emphasis*\n""" + var html = """

    \\emphasis

    \n""" + assert md_to_html(md) == html + end + + fun test295 is test do + var md = """foo\\\nbar\n""" + var html = """

    foo
    \nbar

    \n""" + assert md_to_html(md) == html + end + + fun test296 is test do + var md = """`` \\[\\` ``\n""" + var html = """

    \\[\\`

    \n""" + assert md_to_html(md) == html + end + + fun test297 is test do + var md = """ \\[\\]\n""" + var html = """
    \\[\\]\n
    \n""" + assert md_to_html(md) == html + end + + fun test298 is test do + var md = """~~~\n\\[\\]\n~~~\n""" + var html = """
    \\[\\]\n
    \n""" + assert md_to_html(md) == html + end + + fun test299 is test do + var md = """\n""" + var html = """

    http://example.com?find=\\*

    \n""" + assert md_to_html(md) == html + end + + fun test300 is test do + var md = """\n""" + var html = """\n""" + assert md_to_html(md) == html + end + + fun test301 is test do + var md = """[foo](/bar\\* "ti\\*tle")\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test302 is test do + var md = """[foo]\n\n[foo]: /bar\\* "ti\\*tle"\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test303 is test do + var md = """``` foo\\+bar\nfoo\n```\n""" + var html = """
    foo\n
    \n""" + assert md_to_html(md) == html + end +end diff --git a/lib/markdown2/tests/test_commonmark_blank_lines.nit b/lib/markdown2/tests/test_commonmark_blank_lines.nit new file mode 100644 index 0000000..f294684 --- /dev/null +++ b/lib/markdown2/tests/test_commonmark_blank_lines.nit @@ -0,0 +1,28 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module test_commonmark_blank_lines is test + +import test_markdown + +class TestCommonmarkBlankLines + super TestMarkdownHtml + test + + fun test190 is test do + var md = """ \n\naaa\n \n\n# aaa\n\n \n""" + var html = """

    aaa

    \n

    aaa

    \n""" + assert md_to_html(md) == html + end +end diff --git a/lib/markdown2/tests/test_commonmark_block_quotes.nit b/lib/markdown2/tests/test_commonmark_block_quotes.nit new file mode 100644 index 0000000..db9542f --- /dev/null +++ b/lib/markdown2/tests/test_commonmark_block_quotes.nit @@ -0,0 +1,172 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module test_commonmark_block_quotes is test + +import test_markdown + +class TestCommonmarkBlockQuotes + super TestMarkdownHtml + test + + fun test191 is test do + var md = """> # Foo\n> bar\n> baz\n""" + var html = """
    \n

    Foo

    \n

    bar\nbaz

    \n
    \n""" + assert md_to_html(md) == html + end + + fun test192 is test do + var md = """># Foo\n>bar\n> baz\n""" + var html = """
    \n

    Foo

    \n

    bar\nbaz

    \n
    \n""" + assert md_to_html(md) == html + end + + fun test193 is test do + var md = """ > # Foo\n > bar\n > baz\n""" + var html = """
    \n

    Foo

    \n

    bar\nbaz

    \n
    \n""" + assert md_to_html(md) == html + end + + fun test194 is test do + var md = """ > # Foo\n > bar\n > baz\n""" + var html = """
    > # Foo\n> bar\n> baz\n
    \n""" + assert md_to_html(md) == html + end + + fun test195 is test do + var md = """> # Foo\n> bar\nbaz\n""" + var html = """
    \n

    Foo

    \n

    bar\nbaz

    \n
    \n""" + assert md_to_html(md) == html + end + + fun test196 is test do + var md = """> bar\nbaz\n> foo\n""" + var html = """
    \n

    bar\nbaz\nfoo

    \n
    \n""" + assert md_to_html(md) == html + end + + fun test197 is test do + var md = """> foo\n---\n""" + var html = """
    \n

    foo

    \n
    \n
    \n""" + assert md_to_html(md) == html + end + + fun test198 is test do + var md = """> - foo\n- bar\n""" + var html = """
    \n
      \n
    • foo
    • \n
    \n
    \n
      \n
    • bar
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test199 is test do + var md = """> foo\n bar\n""" + var html = """
    \n
    foo\n
    \n
    \n
    bar\n
    \n""" + assert md_to_html(md) == html + end + + fun test200 is test do + var md = """> ```\nfoo\n```\n""" + var html = """
    \n
    \n
    \n

    foo

    \n
    \n""" + assert md_to_html(md) == html + end + + fun test201 is test do + var md = """> foo\n - bar\n""" + var html = """
    \n

    foo\n- bar

    \n
    \n""" + assert md_to_html(md) == html + end + + fun test202 is test do + var md = """>\n""" + var html = """
    \n
    \n""" + assert md_to_html(md) == html + end + + fun test203 is test do + var md = """>\n> \n> \n""" + var html = """
    \n
    \n""" + assert md_to_html(md) == html + end + + fun test204 is test do + var md = """>\n> foo\n> \n""" + var html = """
    \n

    foo

    \n
    \n""" + assert md_to_html(md) == html + end + + fun test205 is test do + var md = """> foo\n\n> bar\n""" + var html = """
    \n

    foo

    \n
    \n
    \n

    bar

    \n
    \n""" + assert md_to_html(md) == html + end + + fun test206 is test do + var md = """> foo\n> bar\n""" + var html = """
    \n

    foo\nbar

    \n
    \n""" + assert md_to_html(md) == html + end + + fun test207 is test do + var md = """> foo\n>\n> bar\n""" + var html = """
    \n

    foo

    \n

    bar

    \n
    \n""" + assert md_to_html(md) == html + end + + fun test208 is test do + var md = """foo\n> bar\n""" + var html = """

    foo

    \n
    \n

    bar

    \n
    \n""" + assert md_to_html(md) == html + end + + fun test209 is test do + var md = """> aaa\n***\n> bbb\n""" + var html = """
    \n

    aaa

    \n
    \n
    \n
    \n

    bbb

    \n
    \n""" + assert md_to_html(md) == html + end + + fun test210 is test do + var md = """> bar\nbaz\n""" + var html = """
    \n

    bar\nbaz

    \n
    \n""" + assert md_to_html(md) == html + end + + fun test211 is test do + var md = """> bar\n\nbaz\n""" + var html = """
    \n

    bar

    \n
    \n

    baz

    \n""" + assert md_to_html(md) == html + end + + fun test212 is test do + var md = """> bar\n>\nbaz\n""" + var html = """
    \n

    bar

    \n
    \n

    baz

    \n""" + assert md_to_html(md) == html + end + + fun test213 is test do + var md = """> > > foo\nbar\n""" + var html = """
    \n
    \n
    \n

    foo\nbar

    \n
    \n
    \n
    \n""" + assert md_to_html(md) == html + end + + fun test214 is test do + var md = """>>> foo\n> bar\n>>baz\n""" + var html = """
    \n
    \n
    \n

    foo\nbar\nbaz

    \n
    \n
    \n
    \n""" + assert md_to_html(md) == html + end + + fun test215 is test do + var md = """> code\n\n> not code\n""" + var html = """
    \n
    code\n
    \n
    \n
    \n

    not code

    \n
    \n""" + assert md_to_html(md) == html + end +end diff --git a/lib/markdown2/tests/test_commonmark_code_spans.nit b/lib/markdown2/tests/test_commonmark_code_spans.nit new file mode 100644 index 0000000..edcf96b --- /dev/null +++ b/lib/markdown2/tests/test_commonmark_code_spans.nit @@ -0,0 +1,124 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module test_commonmark_code_spans is test + +import test_markdown + +class TestCommonmarkCodeSpans + super TestMarkdownHtml + test + + fun test316 is test do + var md = """`foo`\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test317 is test do + var md = """`` foo ` bar ``\n""" + var html = """

    foo ` bar

    \n""" + assert md_to_html(md) == html + end + + fun test318 is test do + var md = """` `` `\n""" + var html = """

    ``

    \n""" + assert md_to_html(md) == html + end + + fun test319 is test do + var md = """``\nfoo\n``\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test320 is test do + var md = """`foo bar\n baz`\n""" + var html = """

    foo bar baz

    \n""" + assert md_to_html(md) == html + end + + fun test321 is test do + var md = """`a  b`\n""" + var html = """

    a  b

    \n""" + assert md_to_html(md) == html + end + + fun test322 is test do + var md = """`foo `` bar`\n""" + var html = """

    foo `` bar

    \n""" + assert md_to_html(md) == html + end + + fun test323 is test do + var md = """`foo\\`bar`\n""" + var html = """

    foo\\bar`

    \n""" + assert md_to_html(md) == html + end + + fun test324 is test do + var md = """*foo`*`\n""" + var html = """

    *foo*

    \n""" + assert md_to_html(md) == html + end + + fun test325 is test do + var md = """[not a `link](/foo`)\n""" + var html = """

    [not a link](/foo)

    \n""" + assert md_to_html(md) == html + end + + fun test326 is test do + var md = """``\n""" + var html = """

    <a href="">`

    \n""" + assert md_to_html(md) == html + end + + fun test327 is test do + var md = """
    `\n""" + var html = """

    `

    \n""" + assert md_to_html(md) == html + end + + fun test328 is test do + var md = """``\n""" + var html = """

    <http://foo.bar.baz>`

    \n""" + assert md_to_html(md) == html + end + + fun test329 is test do + var md = """`\n""" + var html = """

    http://foo.bar.`baz`

    \n""" + assert md_to_html(md) == html + end + + fun test330 is test do + var md = """```foo``\n""" + var html = """

    ```foo``

    \n""" + assert md_to_html(md) == html + end + + fun test331 is test do + var md = """`foo\n""" + var html = """

    `foo

    \n""" + assert md_to_html(md) == html + end + + fun test332 is test do + var md = """`foo``bar``\n""" + var html = """

    `foobar

    \n""" + assert md_to_html(md) == html + end +end diff --git a/lib/markdown2/tests/test_commonmark_emphasis_and_strong_emphasis.nit b/lib/markdown2/tests/test_commonmark_emphasis_and_strong_emphasis.nit new file mode 100644 index 0000000..64e317b --- /dev/null +++ b/lib/markdown2/tests/test_commonmark_emphasis_and_strong_emphasis.nit @@ -0,0 +1,796 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module test_commonmark_emphasis_and_strong_emphasis is test + +import test_markdown + +class TestCommonmarkEmphasisAndStrongEmphasis + super TestMarkdownHtml + test + + fun test333 is test do + var md = """*foo bar*\n""" + var html = """

    foo bar

    \n""" + assert md_to_html(md) == html + end + + fun test334 is test do + var md = """a * foo bar*\n""" + var html = """

    a * foo bar*

    \n""" + assert md_to_html(md) == html + end + + fun test335 is test do + var md = """a*"foo"*\n""" + var html = """

    a*"foo"*

    \n""" + assert md_to_html(md) == html + end + + fun test336 is test do + var md = """* a *\n""" + var html = """

    * a *

    \n""" + assert md_to_html(md) == html + end + + fun test337 is test do + var md = """foo*bar*\n""" + var html = """

    foobar

    \n""" + assert md_to_html(md) == html + end + + fun test338 is test do + var md = """5*6*78\n""" + var html = """

    5678

    \n""" + assert md_to_html(md) == html + end + + fun test339 is test do + var md = """_foo bar_\n""" + var html = """

    foo bar

    \n""" + assert md_to_html(md) == html + end + + fun test340 is test do + var md = """_ foo bar_\n""" + var html = """

    _ foo bar_

    \n""" + assert md_to_html(md) == html + end + + fun test341 is test do + var md = """a_"foo"_\n""" + var html = """

    a_"foo"_

    \n""" + assert md_to_html(md) == html + end + + fun test342 is test do + var md = """foo_bar_\n""" + var html = """

    foo_bar_

    \n""" + assert md_to_html(md) == html + end + + fun test343 is test do + var md = """5_6_78\n""" + var html = """

    5_6_78

    \n""" + assert md_to_html(md) == html + end + + fun test344 is test do + var md = """пристаням_стремятся_\n""" + var html = """

    пристаням_стремятся_

    \n""" + assert md_to_html(md) == html + end + + fun test345 is test do + var md = """aa_"bb"_cc\n""" + var html = """

    aa_"bb"_cc

    \n""" + assert md_to_html(md) == html + end + + fun test346 is test do + var md = """foo-_(bar)_\n""" + var html = """

    foo-(bar)

    \n""" + assert md_to_html(md) == html + end + + fun test347 is test do + var md = """_foo*\n""" + var html = """

    _foo*

    \n""" + assert md_to_html(md) == html + end + + fun test348 is test do + var md = """*foo bar *\n""" + var html = """

    *foo bar *

    \n""" + assert md_to_html(md) == html + end + + fun test349 is test do + var md = """*foo bar\n*\n""" + var html = """

    *foo bar\n*

    \n""" + assert md_to_html(md) == html + end + + fun test350 is test do + var md = """*(*foo)\n""" + var html = """

    *(*foo)

    \n""" + assert md_to_html(md) == html + end + + fun test351 is test do + var md = """*(*foo*)*\n""" + var html = """

    (foo)

    \n""" + assert md_to_html(md) == html + end + + fun test352 is test do + var md = """*foo*bar\n""" + var html = """

    foobar

    \n""" + assert md_to_html(md) == html + end + + fun test353 is test do + var md = """_foo bar _\n""" + var html = """

    _foo bar _

    \n""" + assert md_to_html(md) == html + end + + fun test354 is test do + var md = """_(_foo)\n""" + var html = """

    _(_foo)

    \n""" + assert md_to_html(md) == html + end + + fun test355 is test do + var md = """_(_foo_)_\n""" + var html = """

    (foo)

    \n""" + assert md_to_html(md) == html + end + + fun test356 is test do + var md = """_foo_bar\n""" + var html = """

    _foo_bar

    \n""" + assert md_to_html(md) == html + end + + fun test357 is test do + var md = """_пристаням_стремятся\n""" + var html = """

    _пристаням_стремятся

    \n""" + assert md_to_html(md) == html + end + + fun test358 is test do + var md = """_foo_bar_baz_\n""" + var html = """

    foo_bar_baz

    \n""" + assert md_to_html(md) == html + end + + fun test359 is test do + var md = """_(bar)_.\n""" + var html = """

    (bar).

    \n""" + assert md_to_html(md) == html + end + + fun test360 is test do + var md = """**foo bar**\n""" + var html = """

    foo bar

    \n""" + assert md_to_html(md) == html + end + + fun test361 is test do + var md = """** foo bar**\n""" + var html = """

    ** foo bar**

    \n""" + assert md_to_html(md) == html + end + + fun test362 is test do + var md = """a**"foo"**\n""" + var html = """

    a**"foo"**

    \n""" + assert md_to_html(md) == html + end + + fun test363 is test do + var md = """foo**bar**\n""" + var html = """

    foobar

    \n""" + assert md_to_html(md) == html + end + + fun test364 is test do + var md = """__foo bar__\n""" + var html = """

    foo bar

    \n""" + assert md_to_html(md) == html + end + + fun test365 is test do + var md = """__ foo bar__\n""" + var html = """

    __ foo bar__

    \n""" + assert md_to_html(md) == html + end + + fun test366 is test do + var md = """__\nfoo bar__\n""" + var html = """

    __\nfoo bar__

    \n""" + assert md_to_html(md) == html + end + + fun test367 is test do + var md = """a__"foo"__\n""" + var html = """

    a__"foo"__

    \n""" + assert md_to_html(md) == html + end + + fun test368 is test do + var md = """foo__bar__\n""" + var html = """

    foo__bar__

    \n""" + assert md_to_html(md) == html + end + + fun test369 is test do + var md = """5__6__78\n""" + var html = """

    5__6__78

    \n""" + assert md_to_html(md) == html + end + + fun test370 is test do + var md = """пристаням__стремятся__\n""" + var html = """

    пристаням__стремятся__

    \n""" + assert md_to_html(md) == html + end + + fun test371 is test do + var md = """__foo, __bar__, baz__\n""" + var html = """

    foo, bar, baz

    \n""" + assert md_to_html(md) == html + end + + fun test372 is test do + var md = """foo-__(bar)__\n""" + var html = """

    foo-(bar)

    \n""" + assert md_to_html(md) == html + end + + fun test373 is test do + var md = """**foo bar **\n""" + var html = """

    **foo bar **

    \n""" + assert md_to_html(md) == html + end + + fun test374 is test do + var md = """**(**foo)\n""" + var html = """

    **(**foo)

    \n""" + assert md_to_html(md) == html + end + + fun test375 is test do + var md = """*(**foo**)*\n""" + var html = """

    (foo)

    \n""" + assert md_to_html(md) == html + end + + fun test376 is test do + var md = """**Gomphocarpus (*Gomphocarpus physocarpus*, syn.\n*Asclepias physocarpa*)**\n""" + var html = """

    Gomphocarpus (Gomphocarpus physocarpus, syn.\nAsclepias physocarpa)

    \n""" + assert md_to_html(md) == html + end + + fun test377 is test do + var md = """**foo "*bar*" foo**\n""" + var html = """

    foo "bar" foo

    \n""" + assert md_to_html(md) == html + end + + fun test378 is test do + var md = """**foo**bar\n""" + var html = """

    foobar

    \n""" + assert md_to_html(md) == html + end + + fun test379 is test do + var md = """__foo bar __\n""" + var html = """

    __foo bar __

    \n""" + assert md_to_html(md) == html + end + + fun test380 is test do + var md = """__(__foo)\n""" + var html = """

    __(__foo)

    \n""" + assert md_to_html(md) == html + end + + fun test381 is test do + var md = """_(__foo__)_\n""" + var html = """

    (foo)

    \n""" + assert md_to_html(md) == html + end + + fun test382 is test do + var md = """__foo__bar\n""" + var html = """

    __foo__bar

    \n""" + assert md_to_html(md) == html + end + + fun test383 is test do + var md = """__пристаням__стремятся\n""" + var html = """

    __пристаням__стремятся

    \n""" + assert md_to_html(md) == html + end + + fun test384 is test do + var md = """__foo__bar__baz__\n""" + var html = """

    foo__bar__baz

    \n""" + assert md_to_html(md) == html + end + + fun test385 is test do + var md = """__(bar)__.\n""" + var html = """

    (bar).

    \n""" + assert md_to_html(md) == html + end + + fun test386 is test do + var md = """*foo [bar](/url)*\n""" + var html = """

    foo bar

    \n""" + assert md_to_html(md) == html + end + + fun test387 is test do + var md = """*foo\nbar*\n""" + var html = """

    foo\nbar

    \n""" + assert md_to_html(md) == html + end + + fun test388 is test do + var md = """_foo __bar__ baz_\n""" + var html = """

    foo bar baz

    \n""" + assert md_to_html(md) == html + end + + fun test389 is test do + var md = """_foo _bar_ baz_\n""" + var html = """

    foo bar baz

    \n""" + assert md_to_html(md) == html + end + + fun test390 is test do + var md = """__foo_ bar_\n""" + var html = """

    foo bar

    \n""" + assert md_to_html(md) == html + end + + fun test391 is test do + var md = """*foo *bar**\n""" + var html = """

    foo bar

    \n""" + assert md_to_html(md) == html + end + + fun test392 is test do + var md = """*foo **bar** baz*\n""" + var html = """

    foo bar baz

    \n""" + assert md_to_html(md) == html + end + + fun test393 is test do + var md = """*foo**bar**baz*\n""" + var html = """

    foobarbaz

    \n""" + assert md_to_html(md) == html + end + + fun test394 is test do + var md = """*foo**bar*\n""" + var html = """

    foo**bar

    \n""" + assert md_to_html(md) == html + end + + fun test395 is test do + var md = """***foo** bar*\n""" + var html = """

    foo bar

    \n""" + assert md_to_html(md) == html + end + + fun test396 is test do + var md = """*foo **bar***\n""" + var html = """

    foo bar

    \n""" + assert md_to_html(md) == html + end + + fun test397 is test do + var md = """*foo**bar***\n""" + var html = """

    foobar

    \n""" + assert md_to_html(md) == html + end + + fun test398 is test do + var md = """*foo **bar *baz* bim** bop*\n""" + var html = """

    foo bar baz bim bop

    \n""" + assert md_to_html(md) == html + end + + fun test399 is test do + var md = """*foo [*bar*](/url)*\n""" + var html = """

    foo bar

    \n""" + assert md_to_html(md) == html + end + + fun test400 is test do + var md = """** is not an empty emphasis\n""" + var html = """

    ** is not an empty emphasis

    \n""" + assert md_to_html(md) == html + end + + fun test401 is test do + var md = """**** is not an empty strong emphasis\n""" + var html = """

    **** is not an empty strong emphasis

    \n""" + assert md_to_html(md) == html + end + + fun test402 is test do + var md = """**foo [bar](/url)**\n""" + var html = """

    foo bar

    \n""" + assert md_to_html(md) == html + end + + fun test403 is test do + var md = """**foo\nbar**\n""" + var html = """

    foo\nbar

    \n""" + assert md_to_html(md) == html + end + + fun test404 is test do + var md = """__foo _bar_ baz__\n""" + var html = """

    foo bar baz

    \n""" + assert md_to_html(md) == html + end + + fun test405 is test do + var md = """__foo __bar__ baz__\n""" + var html = """

    foo bar baz

    \n""" + assert md_to_html(md) == html + end + + fun test406 is test do + var md = """____foo__ bar__\n""" + var html = """

    foo bar

    \n""" + assert md_to_html(md) == html + end + + fun test407 is test do + var md = """**foo **bar****\n""" + var html = """

    foo bar

    \n""" + assert md_to_html(md) == html + end + + fun test408 is test do + var md = """**foo *bar* baz**\n""" + var html = """

    foo bar baz

    \n""" + assert md_to_html(md) == html + end + + fun test409 is test do + var md = """**foo*bar*baz**\n""" + var html = """

    foobarbaz

    \n""" + assert md_to_html(md) == html + end + + fun test410 is test do + var md = """***foo* bar**\n""" + var html = """

    foo bar

    \n""" + assert md_to_html(md) == html + end + + fun test411 is test do + var md = """**foo *bar***\n""" + var html = """

    foo bar

    \n""" + assert md_to_html(md) == html + end + + fun test412 is test do + var md = """**foo *bar **baz**\nbim* bop**\n""" + var html = """

    foo bar baz\nbim bop

    \n""" + assert md_to_html(md) == html + end + + fun test413 is test do + var md = """**foo [*bar*](/url)**\n""" + var html = """

    foo bar

    \n""" + assert md_to_html(md) == html + end + + fun test414 is test do + var md = """__ is not an empty emphasis\n""" + var html = """

    __ is not an empty emphasis

    \n""" + assert md_to_html(md) == html + end + + fun test415 is test do + var md = """____ is not an empty strong emphasis\n""" + var html = """

    ____ is not an empty strong emphasis

    \n""" + assert md_to_html(md) == html + end + + fun test416 is test do + var md = """foo ***\n""" + var html = """

    foo ***

    \n""" + assert md_to_html(md) == html + end + + fun test417 is test do + var md = """foo *\\**\n""" + var html = """

    foo *

    \n""" + assert md_to_html(md) == html + end + + fun test418 is test do + var md = """foo *_*\n""" + var html = """

    foo _

    \n""" + assert md_to_html(md) == html + end + + fun test419 is test do + var md = """foo *****\n""" + var html = """

    foo *****

    \n""" + assert md_to_html(md) == html + end + + fun test420 is test do + var md = """foo **\\***\n""" + var html = """

    foo *

    \n""" + assert md_to_html(md) == html + end + + fun test421 is test do + var md = """foo **_**\n""" + var html = """

    foo _

    \n""" + assert md_to_html(md) == html + end + + fun test422 is test do + var md = """**foo*\n""" + var html = """

    *foo

    \n""" + assert md_to_html(md) == html + end + + fun test423 is test do + var md = """*foo**\n""" + var html = """

    foo*

    \n""" + assert md_to_html(md) == html + end + + fun test424 is test do + var md = """***foo**\n""" + var html = """

    *foo

    \n""" + assert md_to_html(md) == html + end + + fun test425 is test do + var md = """****foo*\n""" + var html = """

    ***foo

    \n""" + assert md_to_html(md) == html + end + + fun test426 is test do + var md = """**foo***\n""" + var html = """

    foo*

    \n""" + assert md_to_html(md) == html + end + + fun test427 is test do + var md = """*foo****\n""" + var html = """

    foo***

    \n""" + assert md_to_html(md) == html + end + + fun test428 is test do + var md = """foo ___\n""" + var html = """

    foo ___

    \n""" + assert md_to_html(md) == html + end + + fun test429 is test do + var md = """foo _\\__\n""" + var html = """

    foo _

    \n""" + assert md_to_html(md) == html + end + + fun test430 is test do + var md = """foo _*_\n""" + var html = """

    foo *

    \n""" + assert md_to_html(md) == html + end + + fun test431 is test do + var md = """foo _____\n""" + var html = """

    foo _____

    \n""" + assert md_to_html(md) == html + end + + fun test432 is test do + var md = """foo __\\___\n""" + var html = """

    foo _

    \n""" + assert md_to_html(md) == html + end + + fun test433 is test do + var md = """foo __*__\n""" + var html = """

    foo *

    \n""" + assert md_to_html(md) == html + end + + fun test434 is test do + var md = """__foo_\n""" + var html = """

    _foo

    \n""" + assert md_to_html(md) == html + end + + fun test435 is test do + var md = """_foo__\n""" + var html = """

    foo_

    \n""" + assert md_to_html(md) == html + end + + fun test436 is test do + var md = """___foo__\n""" + var html = """

    _foo

    \n""" + assert md_to_html(md) == html + end + + fun test437 is test do + var md = """____foo_\n""" + var html = """

    ___foo

    \n""" + assert md_to_html(md) == html + end + + fun test438 is test do + var md = """__foo___\n""" + var html = """

    foo_

    \n""" + assert md_to_html(md) == html + end + + fun test439 is test do + var md = """_foo____\n""" + var html = """

    foo___

    \n""" + assert md_to_html(md) == html + end + + fun test440 is test do + var md = """**foo**\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test441 is test do + var md = """*_foo_*\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test442 is test do + var md = """__foo__\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test443 is test do + var md = """_*foo*_\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test444 is test do + var md = """****foo****\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test445 is test do + var md = """____foo____\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test446 is test do + var md = """******foo******\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test447 is test do + var md = """***foo***\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test448 is test do + var md = """_____foo_____\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test449 is test do + var md = """*foo _bar* baz_\n""" + var html = """

    foo _bar baz_

    \n""" + assert md_to_html(md) == html + end + + fun test450 is test do + var md = """*foo __bar *baz bim__ bam*\n""" + var html = """

    foo bar *baz bim bam

    \n""" + assert md_to_html(md) == html + end + + fun test451 is test do + var md = """**foo **bar baz**\n""" + var html = """

    **foo bar baz

    \n""" + assert md_to_html(md) == html + end + + fun test452 is test do + var md = """*foo *bar baz*\n""" + var html = """

    *foo bar baz

    \n""" + assert md_to_html(md) == html + end + + fun test453 is test do + var md = """*[bar*](/url)\n""" + var html = """

    *bar*

    \n""" + assert md_to_html(md) == html + end + + fun test454 is test do + var md = """_foo [bar_](/url)\n""" + var html = """

    _foo bar_

    \n""" + assert md_to_html(md) == html + end + + fun test455 is test do + var md = """*\n""" + var html = """

    *

    \n""" + assert md_to_html(md) == html + end + + fun test456 is test do + var md = """**\n""" + var html = """

    **

    \n""" + assert md_to_html(md) == html + end + + fun test457 is test do + var md = """__\n""" + var html = """

    __

    \n""" + assert md_to_html(md) == html + end + + fun test458 is test do + var md = """*a `*`*\n""" + var html = """

    a *

    \n""" + assert md_to_html(md) == html + end + + fun test459 is test do + var md = """_a `_`_\n""" + var html = """

    a _

    \n""" + assert md_to_html(md) == html + end + + fun test460 is test do + var md = """**a\n""" + var html = """

    **ahttp://foo.bar/?q=**

    \n""" + assert md_to_html(md) == html + end + + fun test461 is test do + var md = """__a\n""" + var html = """

    __ahttp://foo.bar/?q=__

    \n""" + assert md_to_html(md) == html + end +end diff --git a/lib/markdown2/tests/test_commonmark_entity_and_numeric_character_references.nit b/lib/markdown2/tests/test_commonmark_entity_and_numeric_character_references.nit new file mode 100644 index 0000000..f61edd4 --- /dev/null +++ b/lib/markdown2/tests/test_commonmark_entity_and_numeric_character_references.nit @@ -0,0 +1,58 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module test_commonmark_entity_and_numeric_character_references is test + +import test_markdown + +class TestCommonmarkEntityAndNumericCharacterReferences + super TestMarkdownHtml + test + + fun test307 is test do + var md = """  &x; &#; &#x;\n�\n&#abcdef0;\n&ThisIsNotDefined; &hi?;\n""" + var html = """

    &nbsp &x; &#; &#x;\n&#987654321;\n&#abcdef0;\n&ThisIsNotDefined; &hi?;

    \n""" + assert md_to_html(md) == html + end + + fun test308 is test do + var md = """©\n""" + var html = """

    &copy

    \n""" + assert md_to_html(md) == html + end + + fun test309 is test do + var md = """&MadeUpEntity;\n""" + var html = """

    &MadeUpEntity;

    \n""" + assert md_to_html(md) == html + end + + fun test310 is test do + var md = """\n""" + var html = """\n""" + assert md_to_html(md) == html + end + + fun test314 is test do + var md = """`föö`\n""" + var html = """

    f&ouml;&ouml;

    \n""" + assert md_to_html(md) == html + end + + fun test315 is test do + var md = """ föfö\n""" + var html = """
    f&ouml;f&ouml;\n
    \n""" + assert md_to_html(md) == html + end +end diff --git a/lib/markdown2/tests/test_commonmark_fenced_code_blocks.nit b/lib/markdown2/tests/test_commonmark_fenced_code_blocks.nit new file mode 100644 index 0000000..2d7072a --- /dev/null +++ b/lib/markdown2/tests/test_commonmark_fenced_code_blocks.nit @@ -0,0 +1,190 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module test_commonmark_fenced_code_blocks is test + +import test_markdown + +class TestCommonmarkFencedCodeBlocks + super TestMarkdownHtml + test + + fun test88 is test do + var md = """```\n<\n >\n```\n""" + var html = """
    <\n >\n
    \n""" + assert md_to_html(md) == html + end + + fun test89 is test do + var md = """~~~\n<\n >\n~~~\n""" + var html = """
    <\n >\n
    \n""" + assert md_to_html(md) == html + end + + fun test90 is test do + var md = """``\nfoo\n``\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test91 is test do + var md = """```\naaa\n~~~\n```\n""" + var html = """
    aaa\n~~~\n
    \n""" + assert md_to_html(md) == html + end + + fun test92 is test do + var md = """~~~\naaa\n```\n~~~\n""" + var html = """
    aaa\n```\n
    \n""" + assert md_to_html(md) == html + end + + fun test93 is test do + var md = """````\naaa\n```\n``````\n""" + var html = """
    aaa\n```\n
    \n""" + assert md_to_html(md) == html + end + + fun test94 is test do + var md = """~~~~\naaa\n~~~\n~~~~\n""" + var html = """
    aaa\n~~~\n
    \n""" + assert md_to_html(md) == html + end + + fun test95 is test do + var md = """```\n""" + var html = """
    \n""" + assert md_to_html(md) == html + end + + fun test96 is test do + var md = """`````\n\n```\naaa\n""" + var html = """
    \n```\naaa\n
    \n""" + assert md_to_html(md) == html + end + + fun test97 is test do + var md = """> ```\n> aaa\n\nbbb\n""" + var html = """
    \n
    aaa\n
    \n
    \n

    bbb

    \n""" + assert md_to_html(md) == html + end + + fun test98 is test do + var md = """```\n\n \n```\n""" + var html = """
    \n  \n
    \n""" + assert md_to_html(md) == html + end + + fun test99 is test do + var md = """```\n```\n""" + var html = """
    \n""" + assert md_to_html(md) == html + end + + fun test100 is test do + var md = """ ```\n aaa\naaa\n```\n""" + var html = """
    aaa\naaa\n
    \n""" + assert md_to_html(md) == html + end + + fun test101 is test do + var md = """ ```\naaa\n aaa\naaa\n ```\n""" + var html = """
    aaa\naaa\naaa\n
    \n""" + assert md_to_html(md) == html + end + + fun test102 is test do + var md = """ ```\n aaa\n aaa\n aaa\n ```\n""" + var html = """
    aaa\n aaa\naaa\n
    \n""" + assert md_to_html(md) == html + end + + fun test103 is test do + var md = """ ```\n aaa\n ```\n""" + var html = """
    ```\naaa\n```\n
    \n""" + assert md_to_html(md) == html + end + + fun test104 is test do + var md = """```\naaa\n ```\n""" + var html = """
    aaa\n
    \n""" + assert md_to_html(md) == html + end + + fun test105 is test do + var md = """ ```\naaa\n ```\n""" + var html = """
    aaa\n
    \n""" + assert md_to_html(md) == html + end + + fun test106 is test do + var md = """```\naaa\n ```\n""" + var html = """
    aaa\n    ```\n
    \n""" + assert md_to_html(md) == html + end + + fun test107 is test do + var md = """``` ```\naaa\n""" + var html = """

    \naaa

    \n""" + assert md_to_html(md) == html + end + + fun test108 is test do + var md = """~~~~~~\naaa\n~~~ ~~\n""" + var html = """
    aaa\n~~~ ~~\n
    \n""" + assert md_to_html(md) == html + end + + fun test109 is test do + var md = """foo\n```\nbar\n```\nbaz\n""" + var html = """

    foo

    \n
    bar\n
    \n

    baz

    \n""" + assert md_to_html(md) == html + end + + fun test110 is test do + var md = """foo\n---\n~~~\nbar\n~~~\n# baz\n""" + var html = """

    foo

    \n
    bar\n
    \n

    baz

    \n""" + assert md_to_html(md) == html + end + + fun test111 is test do + var md = """```ruby\ndef foo(x)\n return 3\nend\n```\n""" + var html = """
    def foo(x)\n  return 3\nend\n
    \n""" + assert md_to_html(md) == html + end + + fun test112 is test do + var md = """~~~~ ruby startline=3 $%@#$\ndef foo(x)\n return 3\nend\n~~~~~~~\n""" + var html = """
    def foo(x)\n  return 3\nend\n
    \n""" + assert md_to_html(md) == html + end + + fun test113 is test do + var md = """````;\n````\n""" + var html = """
    \n""" + assert md_to_html(md) == html + end + + fun test114 is test do + var md = """``` aa ```\nfoo\n""" + var html = """

    aa\nfoo

    \n""" + assert md_to_html(md) == html + end + + fun test115 is test do + var md = """```\n``` aaa\n```\n""" + var html = """
    ``` aaa\n
    \n""" + assert md_to_html(md) == html + end +end diff --git a/lib/markdown2/tests/test_commonmark_hard_line_breaks.nit b/lib/markdown2/tests/test_commonmark_hard_line_breaks.nit new file mode 100644 index 0000000..7e2336f --- /dev/null +++ b/lib/markdown2/tests/test_commonmark_hard_line_breaks.nit @@ -0,0 +1,112 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module test_commonmark_hard_line_breaks is test + +import test_markdown + +class TestCommonmarkHardLineBreaks + super TestMarkdownHtml + test + + fun test608 is test do + var md = """foo \nbaz\n""" + var html = """

    foo
    \nbaz

    \n""" + assert md_to_html(md) == html + end + + fun test609 is test do + var md = """foo\\\nbaz\n""" + var html = """

    foo
    \nbaz

    \n""" + assert md_to_html(md) == html + end + + fun test610 is test do + var md = """foo \nbaz\n""" + var html = """

    foo
    \nbaz

    \n""" + assert md_to_html(md) == html + end + + fun test611 is test do + var md = """foo \n bar\n""" + var html = """

    foo
    \nbar

    \n""" + assert md_to_html(md) == html + end + + fun test612 is test do + var md = """foo\\\n bar\n""" + var html = """

    foo
    \nbar

    \n""" + assert md_to_html(md) == html + end + + fun test613 is test do + var md = """*foo \nbar*\n""" + var html = """

    foo
    \nbar

    \n""" + assert md_to_html(md) == html + end + + fun test614 is test do + var md = """*foo\\\nbar*\n""" + var html = """

    foo
    \nbar

    \n""" + assert md_to_html(md) == html + end + + fun test615 is test do + var md = """`code \nspan`\n""" + var html = """

    code span

    \n""" + assert md_to_html(md) == html + end + + fun test616 is test do + var md = """`code\\\nspan`\n""" + var html = """

    code\\ span

    \n""" + assert md_to_html(md) == html + end + + fun test617 is test do + var md = """
    \n""" + var html = """

    \n""" + assert md_to_html(md) == html + end + + fun test618 is test do + var md = """\n""" + var html = """

    \n""" + assert md_to_html(md) == html + end + + fun test619 is test do + var md = """foo\\\n""" + var html = """

    foo\\

    \n""" + assert md_to_html(md) == html + end + + fun test620 is test do + var md = """foo \n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test621 is test do + var md = """### foo\\\n""" + var html = """

    foo\\

    \n""" + assert md_to_html(md) == html + end + + fun test622 is test do + var md = """### foo \n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end +end diff --git a/lib/markdown2/tests/test_commonmark_html_blocks.nit b/lib/markdown2/tests/test_commonmark_html_blocks.nit new file mode 100644 index 0000000..5b92555 --- /dev/null +++ b/lib/markdown2/tests/test_commonmark_html_blocks.nit @@ -0,0 +1,280 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module test_commonmark_html_blocks is test + +import test_markdown + +class TestCommonmarkHTMLBlocks + super TestMarkdownHtml + test + + fun test116 is test do + var md = """
    \n
    \n**Hello**,\n\n_world_.\n
    \n
    \n""" + var html = """
    \n
    \n**Hello**,\n

    world.\n

    \n
    \n""" + assert md_to_html(md) == html + end + + fun test117 is test do + var md = """\n \n \n \n
    \n hi\n
    \n\nokay.\n""" + var html = """\n \n \n \n
    \n hi\n
    \n

    okay.

    \n""" + assert md_to_html(md) == html + end + + fun test118 is test do + var md = """
    \n*foo*\n""" + assert md_to_html(md) == html + end + + fun test120 is test do + var md = """
    \n\n*Markdown*\n\n
    \n""" + var html = """
    \n

    Markdown

    \n
    \n""" + assert md_to_html(md) == html + end + + fun test121 is test do + var md = """
    \n
    \n""" + var html = """
    \n
    \n""" + assert md_to_html(md) == html + end + + fun test122 is test do + var md = """
    \n
    \n""" + var html = """
    \n
    \n""" + assert md_to_html(md) == html + end + + fun test123 is test do + var md = """
    \n*foo*\n\n*bar*\n""" + var html = """
    \n*foo*\n

    bar

    \n""" + assert md_to_html(md) == html + end + + fun test124 is test do + var md = """
    \n""" + var html = """\n""" + assert md_to_html(md) == html + end + + fun test128 is test do + var md = """
    \nfoo\n
    \n""" + var html = """
    \nfoo\n
    \n""" + assert md_to_html(md) == html + end + + fun test129 is test do + var md = """
    \n``` c\nint x = 33;\n```\n""" + var html = """
    \n``` c\nint x = 33;\n```\n""" + assert md_to_html(md) == html + end + + fun test130 is test do + var md = """\n*bar*\n\n""" + var html = """\n*bar*\n\n""" + assert md_to_html(md) == html + end + + fun test131 is test do + var md = """\n*bar*\n\n""" + var html = """\n*bar*\n\n""" + assert md_to_html(md) == html + end + + fun test132 is test do + var md = """\n*bar*\n\n""" + var html = """\n*bar*\n\n""" + assert md_to_html(md) == html + end + + fun test133 is test do + var md = """\n*bar*\n""" + var html = """\n*bar*\n""" + assert md_to_html(md) == html + end + + fun test134 is test do + var md = """\n*foo*\n\n""" + var html = """\n*foo*\n\n""" + assert md_to_html(md) == html + end + + fun test135 is test do + var md = """\n\n*foo*\n\n\n""" + var html = """\n

    foo

    \n
    \n""" + assert md_to_html(md) == html + end + + fun test136 is test do + var md = """*foo*\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test137 is test do + var md = """
    \nimport Text.HTML.TagSoup\n\nmain :: IO ()\nmain = print $ parseTags tags\n
    \nokay\n""" + var html = """
    \nimport Text.HTML.TagSoup\n\nmain :: IO ()\nmain = print $ parseTags tags\n
    \n

    okay

    \n""" + assert md_to_html(md) == html + end + + fun test138 is test do + var md = """\nokay\n""" + var html = """\n

    okay

    \n""" + assert md_to_html(md) == html + end + + fun test139 is test do + var md = """\nh1 {color:red;}\n\np {color:blue;}\n\nokay\n""" + var html = """\nh1 {color:red;}\n\np {color:blue;}\n\n

    okay

    \n""" + assert md_to_html(md) == html + end + + fun test140 is test do + var md = """\n\nfoo\n""" + var html = """\n\nfoo\n""" + assert md_to_html(md) == html + end + + fun test141 is test do + var md = """>
    \n> foo\n\nbar\n""" + var html = """
    \n
    \nfoo\n
    \n

    bar

    \n""" + assert md_to_html(md) == html + end + + fun test142 is test do + var md = """-
    \n- foo\n""" + var html = """
      \n
    • \n
      \n
    • \n
    • foo
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test143 is test do + var md = """\n*foo*\n""" + var html = """\n

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test144 is test do + var md = """*bar*\n*baz*\n""" + var html = """*bar*\n

    baz

    \n""" + assert md_to_html(md) == html + end + + fun test145 is test do + var md = """1. *bar*\n""" + var html = """1. *bar*\n""" + assert md_to_html(md) == html + end + + fun test146 is test do + var md = """\nokay\n""" + var html = """\n

    okay

    \n""" + assert md_to_html(md) == html + end + + fun test147 is test do + var md = """';\n\n?>\nokay\n""" + var html = """';\n\n?>\n

    okay

    \n""" + assert md_to_html(md) == html + end + + fun test148 is test do + var md = """\n""" + var html = """\n""" + assert md_to_html(md) == html + end + + fun test149 is test do + var md = """\nokay\n""" + var html = """\n

    okay

    \n""" + assert md_to_html(md) == html + end + + fun test150 is test do + var md = """ \n\n \n""" + var html = """ \n
    <!-- foo -->\n
    \n""" + assert md_to_html(md) == html + end + + fun test151 is test do + var md = """
    \n\n
    \n""" + var html = """
    \n
    <div>\n
    \n""" + assert md_to_html(md) == html + end + + fun test152 is test do + var md = """Foo\n
    \nbar\n
    \n""" + var html = """

    Foo

    \n
    \nbar\n
    \n""" + assert md_to_html(md) == html + end + + fun test153 is test do + var md = """
    \nbar\n
    \n*foo*\n""" + var html = """
    \nbar\n
    \n*foo*\n""" + assert md_to_html(md) == html + end + + fun test154 is test do + var md = """Foo\n\nbaz\n""" + var html = """

    Foo\n\nbaz

    \n""" + assert md_to_html(md) == html + end + + fun test155 is test do + var md = """
    \n\n*Emphasized* text.\n\n
    \n""" + var html = """
    \n

    Emphasized text.

    \n
    \n""" + assert md_to_html(md) == html + end + + fun test156 is test do + var md = """
    \n*Emphasized* text.\n
    \n""" + var html = """
    \n*Emphasized* text.\n
    \n""" + assert md_to_html(md) == html + end + + fun test157 is test do + var md = """\n\n\n\n\n\n\n\n
    \nHi\n
    \n""" + var html = """\n\n\n\n
    \nHi\n
    \n""" + assert md_to_html(md) == html + end + + fun test158 is test do + var md = """\n\n \n\n \n\n \n\n
    \n Hi\n
    \n""" + var html = """\n \n
    <td>\n  Hi\n</td>\n
    \n \n
    \n""" + assert md_to_html(md) == html + end +end diff --git a/lib/markdown2/tests/test_commonmark_images.nit b/lib/markdown2/tests/test_commonmark_images.nit new file mode 100644 index 0000000..e75f4c1 --- /dev/null +++ b/lib/markdown2/tests/test_commonmark_images.nit @@ -0,0 +1,154 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module test_commonmark_images is test + +import test_markdown + +class TestCommonmarkImages + super TestMarkdownHtml + test + + fun test546 is test do + var md = """![foo](/url "title")\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test547 is test do + var md = """![foo *bar*]\n\n[foo *bar*]: train.jpg "train & tracks"\n""" + var html = """

    foo bar

    \n""" + assert md_to_html(md) == html + end + + fun test548 is test do + var md = """![foo ![bar](/url)](/url2)\n""" + var html = """

    foo bar

    \n""" + assert md_to_html(md) == html + end + + fun test549 is test do + var md = """![foo [bar](/url)](/url2)\n""" + var html = """

    foo bar

    \n""" + assert md_to_html(md) == html + end + + fun test550 is test do + var md = """![foo *bar*][]\n\n[foo *bar*]: train.jpg "train & tracks"\n""" + var html = """

    foo bar

    \n""" + assert md_to_html(md) == html + end + + fun test551 is test do + var md = """![foo *bar*][foobar]\n\n[FOOBAR]: train.jpg "train & tracks"\n""" + var html = """

    foo bar

    \n""" + assert md_to_html(md) == html + end + + fun test552 is test do + var md = """![foo](train.jpg)\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test553 is test do + var md = """My ![foo bar](/path/to/train.jpg "title" )\n""" + var html = """

    My foo bar

    \n""" + assert md_to_html(md) == html + end + + fun test554 is test do + var md = """![foo]()\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test555 is test do + var md = """![](/url)\n""" + var html = """

    \n""" + assert md_to_html(md) == html + end + + fun test556 is test do + var md = """![foo][bar]\n\n[bar]: /url\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test557 is test do + var md = """![foo][bar]\n\n[BAR]: /url\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test558 is test do + var md = """![foo][]\n\n[foo]: /url "title"\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test559 is test do + var md = """![*foo* bar][]\n\n[*foo* bar]: /url "title"\n""" + var html = """

    foo bar

    \n""" + assert md_to_html(md) == html + end + + fun test560 is test do + var md = """![Foo][]\n\n[foo]: /url "title"\n""" + var html = """

    Foo

    \n""" + assert md_to_html(md) == html + end + + fun test561 is test do + var md = """![foo] \n[]\n\n[foo]: /url "title"\n""" + var html = """

    foo\n[]

    \n""" + assert md_to_html(md) == html + end + + fun test562 is test do + var md = """![foo]\n\n[foo]: /url "title"\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test563 is test do + var md = """![*foo* bar]\n\n[*foo* bar]: /url "title"\n""" + var html = """

    foo bar

    \n""" + assert md_to_html(md) == html + end + + fun test564 is test do + var md = """![[foo]]\n\n[[foo]]: /url "title"\n""" + var html = """

    ![[foo]]

    \n

    [[foo]]: /url "title"

    \n""" + assert md_to_html(md) == html + end + + fun test565 is test do + var md = """![Foo]\n\n[foo]: /url "title"\n""" + var html = """

    Foo

    \n""" + assert md_to_html(md) == html + end + + fun test566 is test do + var md = """!\\[foo]\n\n[foo]: /url "title"\n""" + var html = """

    ![foo]

    \n""" + assert md_to_html(md) == html + end + + fun test567 is test do + var md = """\\![foo]\n\n[foo]: /url "title"\n""" + var html = """

    !foo

    \n""" + assert md_to_html(md) == html + end +end diff --git a/lib/markdown2/tests/test_commonmark_indented_code_blocks.nit b/lib/markdown2/tests/test_commonmark_indented_code_blocks.nit new file mode 100644 index 0000000..0c8bf2f --- /dev/null +++ b/lib/markdown2/tests/test_commonmark_indented_code_blocks.nit @@ -0,0 +1,94 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module test_commonmark_indented_code_blocks is test + +import test_markdown + +class TestCommonmarkIndentedCodeBlocks + super TestMarkdownHtml + test + + fun test76 is test do + var md = """ a simple\n indented code block\n""" + var html = """
    a simple\n  indented code block\n
    \n""" + assert md_to_html(md) == html + end + + fun test77 is test do + var md = """ - foo\n\n bar\n""" + var html = """
      \n
    • \n

      foo

      \n

      bar

      \n
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test78 is test do + var md = """1. foo\n\n - bar\n""" + var html = """
      \n
    1. \n

      foo

      \n
        \n
      • bar
      • \n
      \n
    2. \n
    \n""" + assert md_to_html(md) == html + end + + fun test79 is test do + var md = """ \n *hi*\n\n - one\n""" + var html = """
    <a/>\n*hi*\n\n- one\n
    \n""" + assert md_to_html(md) == html + end + + fun test80 is test do + var md = """ chunk1\n\n chunk2\n \n \n \n chunk3\n""" + var html = """
    chunk1\n\nchunk2\n\n\n\nchunk3\n
    \n""" + assert md_to_html(md) == html + end + + fun test81 is test do + var md = """ chunk1\n \n chunk2\n""" + var html = """
    chunk1\n  \n  chunk2\n
    \n""" + assert md_to_html(md) == html + end + + fun test82 is test do + var md = """Foo\n bar\n\n""" + var html = """

    Foo\nbar

    \n""" + assert md_to_html(md) == html + end + + fun test83 is test do + var md = """ foo\nbar\n""" + var html = """
    foo\n
    \n

    bar

    \n""" + assert md_to_html(md) == html + end + + fun test84 is test do + var md = """# Heading\n foo\nHeading\n------\n foo\n----\n""" + var html = """

    Heading

    \n
    foo\n
    \n

    Heading

    \n
    foo\n
    \n
    \n""" + assert md_to_html(md) == html + end + + fun test85 is test do + var md = """ foo\n bar\n""" + var html = """
        foo\nbar\n
    \n""" + assert md_to_html(md) == html + end + + fun test86 is test do + var md = """\n \n foo\n \n\n""" + var html = """
    foo\n
    \n""" + assert md_to_html(md) == html + end + + fun test87 is test do + var md = """ foo \n""" + var html = """
    foo  \n
    \n""" + assert md_to_html(md) == html + end +end diff --git a/lib/markdown2/tests/test_commonmark_inlines.nit b/lib/markdown2/tests/test_commonmark_inlines.nit new file mode 100644 index 0000000..ac13156 --- /dev/null +++ b/lib/markdown2/tests/test_commonmark_inlines.nit @@ -0,0 +1,28 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module test_commonmark_inlines is test + +import test_markdown + +class TestCommonmarkInlines + super TestMarkdownHtml + test + + fun test290 is test do + var md = """`hi`lo`\n""" + var html = """

    hilo`

    \n""" + assert md_to_html(md) == html + end +end diff --git a/lib/markdown2/tests/test_commonmark_link_reference_definitions.nit b/lib/markdown2/tests/test_commonmark_link_reference_definitions.nit new file mode 100644 index 0000000..ebd19a4 --- /dev/null +++ b/lib/markdown2/tests/test_commonmark_link_reference_definitions.nit @@ -0,0 +1,154 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module test_commonmark_link_reference_definitions is test + +import test_markdown + +class TestCommonmarkLinkReferenceDefinitions + super TestMarkdownHtml + test + + fun test159 is test do + var md = """[foo]: /url "title"\n\n[foo]\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test160 is test do + var md = """ [foo]: \n /url \n 'the title' \n\n[foo]\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test161 is test do + var md = """[Foo*bar\\]]:my_(url) 'title (with parens)'\n\n[Foo*bar\\]]\n""" + var html = """

    Foo*bar]

    \n""" + assert md_to_html(md) == html + end + + fun test162 is test do + var md = """[Foo bar]:\n\n'title'\n\n[Foo bar]\n""" + var html = """

    Foo bar

    \n""" + assert md_to_html(md) == html + end + + fun test163 is test do + var md = """[foo]: /url '\ntitle\nline1\nline2\n'\n\n[foo]\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test164 is test do + var md = """[foo]: /url 'title\n\nwith blank line'\n\n[foo]\n""" + var html = """

    [foo]: /url 'title

    \n

    with blank line'

    \n

    [foo]

    \n""" + assert md_to_html(md) == html + end + + fun test165 is test do + var md = """[foo]:\n/url\n\n[foo]\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test166 is test do + var md = """[foo]:\n\n[foo]\n""" + var html = """

    [foo]:

    \n

    [foo]

    \n""" + assert md_to_html(md) == html + end + + fun test167 is test do + var md = """[foo]: /url\\bar\\*baz "foo\\"bar\\baz"\n\n[foo]\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test168 is test do + var md = """[foo]\n\n[foo]: url\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test169 is test do + var md = """[foo]\n\n[foo]: first\n[foo]: second\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test170 is test do + var md = """[FOO]: /url\n\n[Foo]\n""" + var html = """

    Foo

    \n""" + assert md_to_html(md) == html + end + + fun test172 is test do + var md = """[foo]: /url\n""" + var html = """""" + assert md_to_html(md) == html + end + + fun test173 is test do + var md = """[\nfoo\n]: /url\nbar\n""" + var html = """

    bar

    \n""" + assert md_to_html(md) == html + end + + fun test174 is test do + var md = """[foo]: /url "title" ok\n""" + var html = """

    [foo]: /url "title" ok

    \n""" + assert md_to_html(md) == html + end + + fun test175 is test do + var md = """[foo]: /url\n"title" ok\n""" + var html = """

    "title" ok

    \n""" + assert md_to_html(md) == html + end + + fun test176 is test do + var md = """ [foo]: /url "title"\n\n[foo]\n""" + var html = """
    [foo]: /url "title"\n
    \n

    [foo]

    \n""" + assert md_to_html(md) == html + end + + fun test177 is test do + var md = """```\n[foo]: /url\n```\n\n[foo]\n""" + var html = """
    [foo]: /url\n
    \n

    [foo]

    \n""" + assert md_to_html(md) == html + end + + fun test178 is test do + var md = """Foo\n[bar]: /baz\n\n[bar]\n""" + var html = """

    Foo\n[bar]: /baz

    \n

    [bar]

    \n""" + assert md_to_html(md) == html + end + + fun test179 is test do + var md = """# [Foo]\n[foo]: /url\n> bar\n""" + var html = """

    Foo

    \n
    \n

    bar

    \n
    \n""" + assert md_to_html(md) == html + end + + fun test180 is test do + var md = """[foo]: /foo-url "foo"\n[bar]: /bar-url\n "bar"\n[baz]: /baz-url\n\n[foo],\n[bar],\n[baz]\n""" + var html = """

    foo,\nbar,\nbaz

    \n""" + assert md_to_html(md) == html + end + + fun test181 is test do + var md = """[foo]\n\n> [foo]: /url\n""" + var html = """

    foo

    \n
    \n
    \n""" + assert md_to_html(md) == html + end +end diff --git a/lib/markdown2/tests/test_commonmark_links.nit b/lib/markdown2/tests/test_commonmark_links.nit new file mode 100644 index 0000000..bedbbbd --- /dev/null +++ b/lib/markdown2/tests/test_commonmark_links.nit @@ -0,0 +1,514 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module test_commonmark_links is test + +import test_markdown + +class TestCommonmarkLinks + super TestMarkdownHtml + test + + fun test462 is test do + var md = """[link](/uri "title")\n""" + var html = """

    link

    \n""" + assert md_to_html(md) == html + end + + fun test463 is test do + var md = """[link](/uri)\n""" + var html = """

    link

    \n""" + assert md_to_html(md) == html + end + + fun test464 is test do + var md = """[link]()\n""" + var html = """

    link

    \n""" + assert md_to_html(md) == html + end + + fun test465 is test do + var md = """[link](<>)\n""" + var html = """

    link

    \n""" + assert md_to_html(md) == html + end + + fun test466 is test do + var md = """[link](/my uri)\n""" + var html = """

    [link](/my uri)

    \n""" + assert md_to_html(md) == html + end + + fun test467 is test do + var md = """[link]()\n""" + var html = """

    link

    \n""" + assert md_to_html(md) == html + end + + fun test468 is test do + var md = """[link](foo\nbar)\n""" + var html = """

    [link](foo\nbar)

    \n""" + assert md_to_html(md) == html + end + + fun test469 is test do + var md = """[link]()\n""" + var html = """

    [link]()

    \n""" + assert md_to_html(md) == html + end + + fun test470 is test do + var md = """[link](\\(foo\\))\n""" + var html = """

    link

    \n""" + assert md_to_html(md) == html + end + + fun test471 is test do + var md = """[link](foo(and(bar)))\n""" + var html = """

    link

    \n""" + assert md_to_html(md) == html + end + + fun test472 is test do + var md = """[link](foo\\(and\\(bar\\))\n""" + var html = """

    link

    \n""" + assert md_to_html(md) == html + end + + fun test473 is test do + var md = """[link]()\n""" + var html = """

    link

    \n""" + assert md_to_html(md) == html + end + + fun test474 is test do + var md = """[link](foo\\)\\:)\n""" + var html = """

    link

    \n""" + assert md_to_html(md) == html + end + + fun test475 is test do + var md = """[link](#fragment)\n\n[link](http://example.com#fragment)\n\n[link](http://example.com?foo=3#frag)\n""" + var html = """

    link

    \n

    link

    \n

    link

    \n""" + assert md_to_html(md) == html + end + + fun test476 is test do + var md = """[link](foo\\bar)\n""" + var html = """

    link

    \n""" + assert md_to_html(md) == html + end + + fun test478 is test do + var md = """[link]("title")\n""" + var html = """

    link

    \n""" + assert md_to_html(md) == html + end + + fun test479 is test do + var md = """[link](/url "title")\n[link](/url 'title')\n[link](/url (title))\n""" + var html = """

    link\nlink\nlink

    \n""" + assert md_to_html(md) == html + end + + fun test480 is test do + var md = """[link](/url "title \\""")\n""" + var html = """

    link

    \n""" + assert md_to_html(md) == html + end + + fun test481 is test do + var md = """[link](/url "title")\n""" + var html = """

    link

    \n""" + assert md_to_html(md) == html + end + + fun test482 is test do + var md = """[link](/url "title "and" title")\n""" + var html = """

    [link](/url "title "and" title")

    \n""" + assert md_to_html(md) == html + end + + fun test483 is test do + var md = """[link](/url 'title "and" title')\n""" + var html = """

    link

    \n""" + assert md_to_html(md) == html + end + + fun test484 is test do + var md = """[link]( /uri\n "title" )\n""" + var html = """

    link

    \n""" + assert md_to_html(md) == html + end + + fun test485 is test do + var md = """[link] (/uri)\n""" + var html = """

    [link] (/uri)

    \n""" + assert md_to_html(md) == html + end + + fun test486 is test do + var md = """[link [foo [bar]]](/uri)\n""" + var html = """

    link [foo [bar]]

    \n""" + assert md_to_html(md) == html + end + + fun test487 is test do + var md = """[link] bar](/uri)\n""" + var html = """

    [link] bar](/uri)

    \n""" + assert md_to_html(md) == html + end + + fun test488 is test do + var md = """[link [bar](/uri)\n""" + var html = """

    [link bar

    \n""" + assert md_to_html(md) == html + end + + fun test489 is test do + var md = """[link \\[bar](/uri)\n""" + var html = """

    link [bar

    \n""" + assert md_to_html(md) == html + end + + fun test490 is test do + var md = """[link *foo **bar** `#`*](/uri)\n""" + var html = """

    link foo bar #

    \n""" + assert md_to_html(md) == html + end + + fun test491 is test do + var md = """[![moon](moon.jpg)](/uri)\n""" + var html = """

    moon

    \n""" + assert md_to_html(md) == html + end + + fun test492 is test do + var md = """[foo [bar](/uri)](/uri)\n""" + var html = """

    [foo bar](/uri)

    \n""" + assert md_to_html(md) == html + end + + fun test493 is test do + var md = """[foo *[bar [baz](/uri)](/uri)*](/uri)\n""" + var html = """

    [foo [bar baz](/uri)](/uri)

    \n""" + assert md_to_html(md) == html + end + + fun test494 is test do + var md = """![[[foo](uri1)](uri2)](uri3)\n""" + var html = """

    [foo](uri2)

    \n""" + assert md_to_html(md) == html + end + + fun test495 is test do + var md = """*[foo*](/uri)\n""" + var html = """

    *foo*

    \n""" + assert md_to_html(md) == html + end + + fun test496 is test do + var md = """[foo *bar](baz*)\n""" + var html = """

    foo *bar

    \n""" + assert md_to_html(md) == html + end + + fun test497 is test do + var md = """*foo [bar* baz]\n""" + var html = """

    foo [bar baz]

    \n""" + assert md_to_html(md) == html + end + + fun test498 is test do + var md = """[foo \n""" + var html = """

    [foo

    \n""" + assert md_to_html(md) == html + end + + fun test499 is test do + var md = """[foo`](/uri)`\n""" + var html = """

    [foo](/uri)

    \n""" + assert md_to_html(md) == html + end + + fun test500 is test do + var md = """[foo\n""" + var html = """

    [foohttp://example.com/?search=](uri)

    \n""" + assert md_to_html(md) == html + end + + fun test501 is test do + var md = """[foo][bar]\n\n[bar]: /url "title"\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test502 is test do + var md = """[link [foo [bar]]][ref]\n\n[ref]: /uri\n""" + var html = """

    link [foo [bar]]

    \n""" + assert md_to_html(md) == html + end + + fun test503 is test do + var md = """[link \\[bar][ref]\n\n[ref]: /uri\n""" + var html = """

    link [bar

    \n""" + assert md_to_html(md) == html + end + + fun test504 is test do + var md = """[link *foo **bar** `#`*][ref]\n\n[ref]: /uri\n""" + var html = """

    link foo bar #

    \n""" + assert md_to_html(md) == html + end + + fun test505 is test do + var md = """[![moon](moon.jpg)][ref]\n\n[ref]: /uri\n""" + var html = """

    moon

    \n""" + assert md_to_html(md) == html + end + + fun test506 is test do + var md = """[foo [bar](/uri)][ref]\n\n[ref]: /uri\n""" + var html = """

    [foo bar]ref

    \n""" + assert md_to_html(md) == html + end + + fun test507 is test do + var md = """[foo *bar [baz][ref]*][ref]\n\n[ref]: /uri\n""" + var html = """

    [foo bar baz]ref

    \n""" + assert md_to_html(md) == html + end + + fun test508 is test do + var md = """*[foo*][ref]\n\n[ref]: /uri\n""" + var html = """

    *foo*

    \n""" + assert md_to_html(md) == html + end + + fun test509 is test do + var md = """[foo *bar][ref]\n\n[ref]: /uri\n""" + var html = """

    foo *bar

    \n""" + assert md_to_html(md) == html + end + + fun test510 is test do + var md = """[foo \n\n[ref]: /uri\n""" + var html = """

    [foo

    \n""" + assert md_to_html(md) == html + end + + fun test511 is test do + var md = """[foo`][ref]`\n\n[ref]: /uri\n""" + var html = """

    [foo][ref]

    \n""" + assert md_to_html(md) == html + end + + fun test512 is test do + var md = """[foo\n\n[ref]: /uri\n""" + var html = """

    [foohttp://example.com/?search=][ref]

    \n""" + assert md_to_html(md) == html + end + + fun test513 is test do + var md = """[foo][BaR]\n\n[bar]: /url "title"\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test515 is test do + var md = """[Foo\n bar]: /url\n\n[Baz][Foo bar]\n""" + var html = """

    Baz

    \n""" + assert md_to_html(md) == html + end + + fun test516 is test do + var md = """[foo] [bar]\n\n[bar]: /url "title"\n""" + var html = """

    [foo] bar

    \n""" + assert md_to_html(md) == html + end + + fun test517 is test do + var md = """[foo]\n[bar]\n\n[bar]: /url "title"\n""" + var html = """

    [foo]\nbar

    \n""" + assert md_to_html(md) == html + end + + fun test518 is test do + var md = """[foo]: /url1\n\n[foo]: /url2\n\n[bar][foo]\n""" + var html = """

    bar

    \n""" + assert md_to_html(md) == html + end + + fun test519 is test do + var md = """[bar][foo\\!]\n\n[foo!]: /url\n""" + var html = """

    [bar][foo!]

    \n""" + assert md_to_html(md) == html + end + + fun test520 is test do + var md = """[foo][ref[]\n\n[ref[]: /uri\n""" + var html = """

    [foo][ref[]

    \n

    [ref[]: /uri

    \n""" + assert md_to_html(md) == html + end + + fun test521 is test do + var md = """[foo][ref[bar]]\n\n[ref[bar]]: /uri\n""" + var html = """

    [foo][ref[bar]]

    \n

    [ref[bar]]: /uri

    \n""" + assert md_to_html(md) == html + end + + fun test522 is test do + var md = """[[[foo]]]\n\n[[[foo]]]: /url\n""" + var html = """

    [[[foo]]]

    \n

    [[[foo]]]: /url

    \n""" + assert md_to_html(md) == html + end + + fun test523 is test do + var md = """[foo][ref\\[]\n\n[ref\\[]: /uri\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test524 is test do + var md = """[bar\\\\]: /uri\n\n[bar\\\\]\n""" + var html = """

    bar\\

    \n""" + assert md_to_html(md) == html + end + + fun test525 is test do + var md = """[]\n\n[]: /uri\n""" + var html = """

    []

    \n

    []: /uri

    \n""" + assert md_to_html(md) == html + end + + fun test526 is test do + var md = """[\n ]\n\n[\n ]: /uri\n""" + var html = """

    [\n]

    \n

    [\n]: /uri

    \n""" + assert md_to_html(md) == html + end + + fun test527 is test do + var md = """[foo][]\n\n[foo]: /url "title"\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test528 is test do + var md = """[*foo* bar][]\n\n[*foo* bar]: /url "title"\n""" + var html = """

    foo bar

    \n""" + assert md_to_html(md) == html + end + + fun test529 is test do + var md = """[Foo][]\n\n[foo]: /url "title"\n""" + var html = """

    Foo

    \n""" + assert md_to_html(md) == html + end + + fun test530 is test do + var md = """[foo] \n[]\n\n[foo]: /url "title"\n""" + var html = """

    foo\n[]

    \n""" + assert md_to_html(md) == html + end + + fun test531 is test do + var md = """[foo]\n\n[foo]: /url "title"\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test532 is test do + var md = """[*foo* bar]\n\n[*foo* bar]: /url "title"\n""" + var html = """

    foo bar

    \n""" + assert md_to_html(md) == html + end + + fun test533 is test do + var md = """[[*foo* bar]]\n\n[*foo* bar]: /url "title"\n""" + var html = """

    [foo bar]

    \n""" + assert md_to_html(md) == html + end + + fun test534 is test do + var md = """[[bar [foo]\n\n[foo]: /url\n""" + var html = """

    [[bar foo

    \n""" + assert md_to_html(md) == html + end + + fun test535 is test do + var md = """[Foo]\n\n[foo]: /url "title"\n""" + var html = """

    Foo

    \n""" + assert md_to_html(md) == html + end + + fun test536 is test do + var md = """[foo] bar\n\n[foo]: /url\n""" + var html = """

    foo bar

    \n""" + assert md_to_html(md) == html + end + + fun test537 is test do + var md = """\\[foo]\n\n[foo]: /url "title"\n""" + var html = """

    [foo]

    \n""" + assert md_to_html(md) == html + end + + fun test538 is test do + var md = """[foo*]: /url\n\n*[foo*]\n""" + var html = """

    *foo*

    \n""" + assert md_to_html(md) == html + end + + fun test539 is test do + var md = """[foo][bar]\n\n[foo]: /url1\n[bar]: /url2\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test540 is test do + var md = """[foo][]\n\n[foo]: /url1\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test541 is test do + var md = """[foo]()\n\n[foo]: /url1\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test542 is test do + var md = """[foo](not a link)\n\n[foo]: /url1\n""" + var html = """

    foo(not a link)

    \n""" + assert md_to_html(md) == html + end + + fun test543 is test do + var md = """[foo][bar][baz]\n\n[baz]: /url\n""" + var html = """

    [foo]bar

    \n""" + assert md_to_html(md) == html + end + + fun test544 is test do + var md = """[foo][bar][baz]\n\n[baz]: /url1\n[bar]: /url2\n""" + var html = """

    foobaz

    \n""" + assert md_to_html(md) == html + end + + fun test545 is test do + var md = """[foo][bar][baz]\n\n[baz]: /url1\n[foo]: /url2\n""" + var html = """

    [foo]bar

    \n""" + assert md_to_html(md) == html + end +end diff --git a/lib/markdown2/tests/test_commonmark_list_items.nit b/lib/markdown2/tests/test_commonmark_list_items.nit new file mode 100644 index 0000000..b4896ed --- /dev/null +++ b/lib/markdown2/tests/test_commonmark_list_items.nit @@ -0,0 +1,310 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module test_commonmark_list_items is test + +import test_markdown + +class TestCommonmarkListItems + super TestMarkdownHtml + test + + fun test216 is test do + var md = """A paragraph\nwith two lines.\n\n indented code\n\n> A block quote.\n""" + var html = """

    A paragraph\nwith two lines.

    \n
    indented code\n
    \n
    \n

    A block quote.

    \n
    \n""" + assert md_to_html(md) == html + end + + fun test217 is test do + var md = """1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n""" + var html = """
      \n
    1. \n

      A paragraph\nwith two lines.

      \n
      indented code\n
      \n
      \n

      A block quote.

      \n
      \n
    2. \n
    \n""" + assert md_to_html(md) == html + end + + fun test218 is test do + var md = """- one\n\n two\n""" + var html = """
      \n
    • one
    • \n
    \n

    two

    \n""" + assert md_to_html(md) == html + end + + fun test219 is test do + var md = """- one\n\n two\n""" + var html = """
      \n
    • \n

      one

      \n

      two

      \n
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test220 is test do + var md = """ - one\n\n two\n""" + var html = """
      \n
    • one
    • \n
    \n
     two\n
    \n""" + assert md_to_html(md) == html + end + + fun test221 is test do + var md = """ - one\n\n two\n""" + var html = """
      \n
    • \n

      one

      \n

      two

      \n
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test222 is test do + var md = """ > > 1. one\n>>\n>> two\n""" + var html = """
    \n
    \n
      \n
    1. \n

      one

      \n

      two

      \n
    2. \n
    \n
    \n
    \n""" + assert md_to_html(md) == html + end + + fun test223 is test do + var md = """>>- one\n>>\n > > two\n""" + var html = """
    \n
    \n
      \n
    • one
    • \n
    \n

    two

    \n
    \n
    \n""" + assert md_to_html(md) == html + end + + fun test224 is test do + var md = """-one\n\n2.two\n""" + var html = """

    -one

    \n

    2.two

    \n""" + assert md_to_html(md) == html + end + + fun test225 is test do + var md = """- foo\n\n\n bar\n""" + var html = """
      \n
    • \n

      foo

      \n

      bar

      \n
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test226 is test do + var md = """1. foo\n\n ```\n bar\n ```\n\n baz\n\n > bam\n""" + var html = """
      \n
    1. \n

      foo

      \n
      bar\n
      \n

      baz

      \n
      \n

      bam

      \n
      \n
    2. \n
    \n""" + assert md_to_html(md) == html + end + + fun test227 is test do + var md = """- Foo\n\n bar\n\n\n baz\n""" + var html = """
      \n
    • \n

      Foo

      \n
      bar\n\n\nbaz\n
      \n
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test228 is test do + var md = """123456789. ok\n""" + var html = """
      \n
    1. ok
    2. \n
    \n""" + assert md_to_html(md) == html + end + + fun test229 is test do + var md = """1234567890. not ok\n""" + var html = """

    1234567890. not ok

    \n""" + assert md_to_html(md) == html + end + + fun test230 is test do + var md = """0. ok\n""" + var html = """
      \n
    1. ok
    2. \n
    \n""" + assert md_to_html(md) == html + end + + fun test231 is test do + var md = """003. ok\n""" + var html = """
      \n
    1. ok
    2. \n
    \n""" + assert md_to_html(md) == html + end + + fun test232 is test do + var md = """-1. not ok\n""" + var html = """

    -1. not ok

    \n""" + assert md_to_html(md) == html + end + + fun test233 is test do + var md = """- foo\n\n bar\n""" + var html = """
      \n
    • \n

      foo

      \n
      bar\n
      \n
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test234 is test do + var md = """ 10. foo\n\n bar\n""" + var html = """
      \n
    1. \n

      foo

      \n
      bar\n
      \n
    2. \n
    \n""" + assert md_to_html(md) == html + end + + fun test235 is test do + var md = """ indented code\n\nparagraph\n\n more code\n""" + var html = """
    indented code\n
    \n

    paragraph

    \n
    more code\n
    \n""" + assert md_to_html(md) == html + end + + fun test236 is test do + var md = """1. indented code\n\n paragraph\n\n more code\n""" + var html = """
      \n
    1. \n
      indented code\n
      \n

      paragraph

      \n
      more code\n
      \n
    2. \n
    \n""" + assert md_to_html(md) == html + end + + fun test237 is test do + var md = """1. indented code\n\n paragraph\n\n more code\n""" + var html = """
      \n
    1. \n
       indented code\n
      \n

      paragraph

      \n
      more code\n
      \n
    2. \n
    \n""" + assert md_to_html(md) == html + end + + fun test238 is test do + var md = """ foo\n\nbar\n""" + var html = """

    foo

    \n

    bar

    \n""" + assert md_to_html(md) == html + end + + fun test239 is test do + var md = """- foo\n\n bar\n""" + var html = """
      \n
    • foo
    • \n
    \n

    bar

    \n""" + assert md_to_html(md) == html + end + + fun test240 is test do + var md = """- foo\n\n bar\n""" + var html = """
      \n
    • \n

      foo

      \n

      bar

      \n
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test241 is test do + var md = """-\n foo\n-\n ```\n bar\n ```\n-\n baz\n""" + var html = """
      \n
    • foo
    • \n
    • \n
      bar\n
      \n
    • \n
    • \n
      baz\n
      \n
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test242 is test do + var md = """- \n foo\n""" + var html = """
      \n
    • foo
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test243 is test do + var md = """-\n\n foo\n""" + var html = """
      \n
    • \n
    \n

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test244 is test do + var md = """- foo\n-\n- bar\n""" + var html = """
      \n
    • foo
    • \n
    • \n
    • bar
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test245 is test do + var md = """- foo\n- \n- bar\n""" + var html = """
      \n
    • foo
    • \n
    • \n
    • bar
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test246 is test do + var md = """1. foo\n2.\n3. bar\n""" + var html = """
      \n
    1. foo
    2. \n
    3. \n
    4. bar
    5. \n
    \n""" + assert md_to_html(md) == html + end + + fun test247 is test do + var md = """*\n""" + var html = """
      \n
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test248 is test do + var md = """foo\n*\n\nfoo\n1.\n""" + var html = """

    foo\n*

    \n

    foo\n1.

    \n""" + assert md_to_html(md) == html + end + + fun test249 is test do + var md = """ 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n""" + var html = """
      \n
    1. \n

      A paragraph\nwith two lines.

      \n
      indented code\n
      \n
      \n

      A block quote.

      \n
      \n
    2. \n
    \n""" + assert md_to_html(md) == html + end + + fun test250 is test do + var md = """ 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n""" + var html = """
      \n
    1. \n

      A paragraph\nwith two lines.

      \n
      indented code\n
      \n
      \n

      A block quote.

      \n
      \n
    2. \n
    \n""" + assert md_to_html(md) == html + end + + fun test251 is test do + var md = """ 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n""" + var html = """
      \n
    1. \n

      A paragraph\nwith two lines.

      \n
      indented code\n
      \n
      \n

      A block quote.

      \n
      \n
    2. \n
    \n""" + assert md_to_html(md) == html + end + + fun test252 is test do + var md = """ 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n""" + var html = """
    1.  A paragraph\n    with two lines.\n\n        indented code\n\n    > A block quote.\n
    \n""" + assert md_to_html(md) == html + end + + fun test253 is test do + var md = """ 1. A paragraph\nwith two lines.\n\n indented code\n\n > A block quote.\n""" + var html = """
      \n
    1. \n

      A paragraph\nwith two lines.

      \n
      indented code\n
      \n
      \n

      A block quote.

      \n
      \n
    2. \n
    \n""" + assert md_to_html(md) == html + end + + fun test254 is test do + var md = """ 1. A paragraph\n with two lines.\n""" + var html = """
      \n
    1. A paragraph\nwith two lines.
    2. \n
    \n""" + assert md_to_html(md) == html + end + + fun test255 is test do + var md = """> 1. > Blockquote\ncontinued here.\n""" + var html = """
    \n
      \n
    1. \n
      \n

      Blockquote\ncontinued here.

      \n
      \n
    2. \n
    \n
    \n""" + assert md_to_html(md) == html + end + + fun test256 is test do + var md = """> 1. > Blockquote\n> continued here.\n""" + var html = """
    \n
      \n
    1. \n
      \n

      Blockquote\ncontinued here.

      \n
      \n
    2. \n
    \n
    \n""" + assert md_to_html(md) == html + end + + fun test257 is test do + var md = """- foo\n - bar\n - baz\n - boo\n""" + var html = """
      \n
    • foo\n
        \n
      • bar\n
          \n
        • baz\n
            \n
          • boo
          • \n
          \n
        • \n
        \n
      • \n
      \n
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test258 is test do + var md = """- foo\n - bar\n - baz\n - boo\n""" + var html = """
      \n
    • foo
    • \n
    • bar
    • \n
    • baz
    • \n
    • boo
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test259 is test do + var md = """10) foo\n - bar\n""" + var html = """
      \n
    1. foo\n
        \n
      • bar
      • \n
      \n
    2. \n
    \n""" + assert md_to_html(md) == html + end + + fun test260 is test do + var md = """10) foo\n - bar\n""" + var html = """
      \n
    1. foo
    2. \n
    \n
      \n
    • bar
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test261 is test do + var md = """- - foo\n""" + var html = """
      \n
    • \n
        \n
      • foo
      • \n
      \n
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test262 is test do + var md = """1. - 2. foo\n""" + var html = """
      \n
    1. \n
        \n
      • \n
          \n
        1. foo
        2. \n
        \n
      • \n
      \n
    2. \n
    \n""" + assert md_to_html(md) == html + end + + fun test263 is test do + var md = """- # Foo\n- Bar\n ---\n baz\n""" + var html = """
      \n
    • \n

      Foo

      \n
    • \n
    • \n

      Bar

      \nbaz
    • \n
    \n""" + assert md_to_html(md) == html + end +end diff --git a/lib/markdown2/tests/test_commonmark_lists.nit b/lib/markdown2/tests/test_commonmark_lists.nit new file mode 100644 index 0000000..05ef4d4 --- /dev/null +++ b/lib/markdown2/tests/test_commonmark_lists.nit @@ -0,0 +1,166 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module test_commonmark_lists is test + +import test_markdown + +class TestCommonmarkLists + super TestMarkdownHtml + test + + fun test264 is test do + var md = """- foo\n- bar\n+ baz\n""" + var html = """
      \n
    • foo
    • \n
    • bar
    • \n
    \n
      \n
    • baz
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test265 is test do + var md = """1. foo\n2. bar\n3) baz\n""" + var html = """
      \n
    1. foo
    2. \n
    3. bar
    4. \n
    \n
      \n
    1. baz
    2. \n
    \n""" + assert md_to_html(md) == html + end + + fun test266 is test do + var md = """Foo\n- bar\n- baz\n""" + var html = """

    Foo

    \n
      \n
    • bar
    • \n
    • baz
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test267 is test do + var md = """The number of windows in my house is\n14. The number of doors is 6.\n""" + var html = """

    The number of windows in my house is\n14. The number of doors is 6.

    \n""" + assert md_to_html(md) == html + end + + fun test268 is test do + var md = """The number of windows in my house is\n1. The number of doors is 6.\n""" + var html = """

    The number of windows in my house is

    \n
      \n
    1. The number of doors is 6.
    2. \n
    \n""" + assert md_to_html(md) == html + end + + fun test269 is test do + var md = """- foo\n\n- bar\n\n\n- baz\n""" + var html = """
      \n
    • \n

      foo

      \n
    • \n
    • \n

      bar

      \n
    • \n
    • \n

      baz

      \n
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test270 is test do + var md = """- foo\n - bar\n - baz\n\n\n bim\n""" + var html = """
      \n
    • foo\n
        \n
      • bar\n
          \n
        • \n

          baz

          \n

          bim

          \n
        • \n
        \n
      • \n
      \n
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test271 is test do + var md = """- foo\n- bar\n\n\n\n- baz\n- bim\n""" + var html = """
      \n
    • foo
    • \n
    • bar
    • \n
    \n\n
      \n
    • baz
    • \n
    • bim
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test272 is test do + var md = """- foo\n\n notcode\n\n- foo\n\n\n\n code\n""" + var html = """
      \n
    • \n

      foo

      \n

      notcode

      \n
    • \n
    • \n

      foo

      \n
    • \n
    \n\n
    code\n
    \n""" + assert md_to_html(md) == html + end + + fun test273 is test do + var md = """- a\n - b\n - c\n - d\n - e\n - f\n- g\n""" + var html = """
      \n
    • a
    • \n
    • b
    • \n
    • c
    • \n
    • d
    • \n
    • e
    • \n
    • f
    • \n
    • g
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test274 is test do + var md = """1. a\n\n 2. b\n\n 3. c\n""" + var html = """
      \n
    1. \n

      a

      \n
    2. \n
    3. \n

      b

      \n
    4. \n
    5. \n

      c

      \n
    6. \n
    \n""" + assert md_to_html(md) == html + end + + fun test277 is test do + var md = """- a\n- b\n\n- c\n""" + var html = """
      \n
    • \n

      a

      \n
    • \n
    • \n

      b

      \n
    • \n
    • \n

      c

      \n
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test278 is test do + var md = """* a\n*\n\n* c\n""" + var html = """
      \n
    • \n

      a

      \n
    • \n
    • \n
    • \n

      c

      \n
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test279 is test do + var md = """- a\n- b\n\n c\n- d\n""" + var html = """
      \n
    • \n

      a

      \n
    • \n
    • \n

      b

      \n

      c

      \n
    • \n
    • \n

      d

      \n
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test280 is test do + var md = """- a\n- b\n\n [ref]: /url\n- d\n""" + var html = """
      \n
    • \n

      a

      \n
    • \n
    • \n

      b

      \n
    • \n
    • \n

      d

      \n
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test281 is test do + var md = """- a\n- ```\n b\n\n\n ```\n- c\n""" + var html = """
      \n
    • a
    • \n
    • \n
      b\n\n\n
      \n
    • \n
    • c
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test282 is test do + var md = """- a\n - b\n\n c\n- d\n""" + var html = """
      \n
    • a\n
        \n
      • \n

        b

        \n

        c

        \n
      • \n
      \n
    • \n
    • d
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test283 is test do + var md = """* a\n > b\n >\n* c\n""" + var html = """
      \n
    • a\n
      \n

      b

      \n
      \n
    • \n
    • c
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test284 is test do + var md = """- a\n > b\n ```\n c\n ```\n- d\n""" + var html = """
      \n
    • a\n
      \n

      b

      \n
      \n
      c\n
      \n
    • \n
    • d
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test285 is test do + var md = """- a\n""" + var html = """
      \n
    • a
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test286 is test do + var md = """- a\n - b\n""" + var html = """
      \n
    • a\n
        \n
      • b
      • \n
      \n
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test287 is test do + var md = """1. ```\n foo\n ```\n\n bar\n""" + var html = """
      \n
    1. \n
      foo\n
      \n

      bar

      \n
    2. \n
    \n""" + assert md_to_html(md) == html + end + + fun test288 is test do + var md = """* foo\n * bar\n\n baz\n""" + var html = """
      \n
    • \n

      foo

      \n
        \n
      • bar
      • \n
      \n

      baz

      \n
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test289 is test do + var md = """- a\n - b\n - c\n\n- d\n - e\n - f\n""" + var html = """
      \n
    • \n

      a

      \n
        \n
      • b
      • \n
      • c
      • \n
      \n
    • \n
    • \n

      d

      \n
        \n
      • e
      • \n
      • f
      • \n
      \n
    • \n
    \n""" + assert md_to_html(md) == html + end +end diff --git a/lib/markdown2/tests/test_commonmark_paragraphs.nit b/lib/markdown2/tests/test_commonmark_paragraphs.nit new file mode 100644 index 0000000..6501c95 --- /dev/null +++ b/lib/markdown2/tests/test_commonmark_paragraphs.nit @@ -0,0 +1,70 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module test_commonmark_paragraphs is test + +import test_markdown + +class TestCommonmarkParagraphs + super TestMarkdownHtml + test + + fun test182 is test do + var md = """aaa\n\nbbb\n""" + var html = """

    aaa

    \n

    bbb

    \n""" + assert md_to_html(md) == html + end + + fun test183 is test do + var md = """aaa\nbbb\n\nccc\nddd\n""" + var html = """

    aaa\nbbb

    \n

    ccc\nddd

    \n""" + assert md_to_html(md) == html + end + + fun test184 is test do + var md = """aaa\n\n\nbbb\n""" + var html = """

    aaa

    \n

    bbb

    \n""" + assert md_to_html(md) == html + end + + fun test185 is test do + var md = """ aaa\n bbb\n""" + var html = """

    aaa\nbbb

    \n""" + assert md_to_html(md) == html + end + + fun test186 is test do + var md = """aaa\n bbb\n ccc\n""" + var html = """

    aaa\nbbb\nccc

    \n""" + assert md_to_html(md) == html + end + + fun test187 is test do + var md = """ aaa\nbbb\n""" + var html = """

    aaa\nbbb

    \n""" + assert md_to_html(md) == html + end + + fun test188 is test do + var md = """ aaa\nbbb\n""" + var html = """
    aaa\n
    \n

    bbb

    \n""" + assert md_to_html(md) == html + end + + fun test189 is test do + var md = """aaa \nbbb \n""" + var html = """

    aaa
    \nbbb

    \n""" + assert md_to_html(md) == html + end +end diff --git a/lib/markdown2/tests/test_commonmark_precedence.nit b/lib/markdown2/tests/test_commonmark_precedence.nit new file mode 100644 index 0000000..a9938c0 --- /dev/null +++ b/lib/markdown2/tests/test_commonmark_precedence.nit @@ -0,0 +1,28 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module test_commonmark_precedence is test + +import test_markdown + +class TestCommonmarkPrecedence + super TestMarkdownHtml + test + + fun test12 is test do + var md = """- `one\n- two`\n""" + var html = """
      \n
    • `one
    • \n
    • two`
    • \n
    \n""" + assert md_to_html(md) == html + end +end diff --git a/lib/markdown2/tests/test_commonmark_raw_html.nit b/lib/markdown2/tests/test_commonmark_raw_html.nit new file mode 100644 index 0000000..9e05a46 --- /dev/null +++ b/lib/markdown2/tests/test_commonmark_raw_html.nit @@ -0,0 +1,148 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module test_commonmark_raw_html is test + +import test_markdown + +class TestCommonmarkRawHTML + super TestMarkdownHtml + test + + fun test587 is test do + var md = """\n""" + var html = """

    \n""" + assert md_to_html(md) == html + end + + fun test588 is test do + var md = """\n""" + var html = """

    \n""" + assert md_to_html(md) == html + end + + fun test589 is test do + var md = """\n""" + var html = """

    \n""" + assert md_to_html(md) == html + end + + fun test590 is test do + var md = """\n""" + var html = """

    \n""" + assert md_to_html(md) == html + end + + fun test591 is test do + var md = """Foo \n""" + var html = """

    Foo

    \n""" + assert md_to_html(md) == html + end + + fun test592 is test do + var md = """<33> <__>\n""" + var html = """

    <33> <__>

    \n""" + assert md_to_html(md) == html + end + + fun test593 is test do + var md = """
    \n""" + var html = """

    <a h*#ref="hi">

    \n""" + assert md_to_html(md) == html + end + + fun test594 is test do + var md = """
    <a href="hi'> <a href=hi'>

    \n""" + assert md_to_html(md) == html + end + + fun test595 is test do + var md = """< a><\nfoo>\n\n""" + var html = """

    < a><\nfoo><bar/ >\n<foo bar=baz\nbim!bop />

    \n""" + assert md_to_html(md) == html + end + + fun test596 is test do + var md = """
    \n""" + var html = """

    <a href='bar'title=title>

    \n""" + assert md_to_html(md) == html + end + + fun test597 is test do + var md = """
    \n""" + var html = """

    \n""" + assert md_to_html(md) == html + end + + fun test598 is test do + var md = """\n""" + var html = """

    </a href="foo">

    \n""" + assert md_to_html(md) == html + end + + fun test599 is test do + var md = """foo \n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test600 is test do + var md = """foo \n""" + var html = """

    foo <!-- not a comment -- two hyphens -->

    \n""" + assert md_to_html(md) == html + end + + fun test601 is test do + var md = """foo foo -->\n\nfoo \n""" + var html = """

    foo <!--> foo -->

    \n

    foo <!-- foo--->

    \n""" + assert md_to_html(md) == html + end + + fun test602 is test do + var md = """foo \n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test603 is test do + var md = """foo \n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test604 is test do + var md = """foo &<]]>\n""" + var html = """

    foo &<]]>

    \n""" + assert md_to_html(md) == html + end + + fun test605 is test do + var md = """foo \n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test606 is test do + var md = """foo \n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test607 is test do + var md = """\n""" + var html = """

    <a href=""">

    \n""" + assert md_to_html(md) == html + end +end diff --git a/lib/markdown2/tests/test_commonmark_setext_headings.nit b/lib/markdown2/tests/test_commonmark_setext_headings.nit new file mode 100644 index 0000000..c92f4d0 --- /dev/null +++ b/lib/markdown2/tests/test_commonmark_setext_headings.nit @@ -0,0 +1,178 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module test_commonmark_setext_headings is test + +import test_markdown + +class TestCommonmarkSetextHeadings + super TestMarkdownHtml + test + + fun test50 is test do + var md = """Foo *bar*\n=========\n\nFoo *bar*\n---------\n""" + var html = """

    Foo bar

    \n

    Foo bar

    \n""" + assert md_to_html(md) == html + end + + fun test51 is test do + var md = """Foo *bar\nbaz*\n====\n""" + var html = """

    Foo bar\nbaz

    \n""" + assert md_to_html(md) == html + end + + fun test52 is test do + var md = """Foo\n-------------------------\n\nFoo\n=\n""" + var html = """

    Foo

    \n

    Foo

    \n""" + assert md_to_html(md) == html + end + + fun test53 is test do + var md = """ Foo\n---\n\n Foo\n-----\n\n Foo\n ===\n""" + var html = """

    Foo

    \n

    Foo

    \n

    Foo

    \n""" + assert md_to_html(md) == html + end + + fun test54 is test do + var md = """ Foo\n ---\n\n Foo\n---\n""" + var html = """
    Foo\n---\n\nFoo\n
    \n
    \n""" + assert md_to_html(md) == html + end + + fun test55 is test do + var md = """Foo\n ---- \n""" + var html = """

    Foo

    \n""" + assert md_to_html(md) == html + end + + fun test56 is test do + var md = """Foo\n ---\n""" + var html = """

    Foo\n---

    \n""" + assert md_to_html(md) == html + end + + fun test57 is test do + var md = """Foo\n= =\n\nFoo\n--- -\n""" + var html = """

    Foo\n= =

    \n

    Foo

    \n
    \n""" + assert md_to_html(md) == html + end + + fun test58 is test do + var md = """Foo \n-----\n""" + var html = """

    Foo

    \n""" + assert md_to_html(md) == html + end + + fun test59 is test do + var md = """Foo\\\n----\n""" + var html = """

    Foo\\

    \n""" + assert md_to_html(md) == html + end + + fun test60 is test do + var md = """`Foo\n----\n`\n\n
    \n""" + var html = """

    `Foo

    \n

    `

    \n

    <a title="a lot

    \n

    of dashes"/>

    \n""" + assert md_to_html(md) == html + end + + fun test61 is test do + var md = """> Foo\n---\n""" + var html = """
    \n

    Foo

    \n
    \n
    \n""" + assert md_to_html(md) == html + end + + fun test62 is test do + var md = """> foo\nbar\n===\n""" + var html = """
    \n

    foo\nbar\n===

    \n
    \n""" + assert md_to_html(md) == html + end + + fun test63 is test do + var md = """- Foo\n---\n""" + var html = """
      \n
    • Foo
    • \n
    \n
    \n""" + assert md_to_html(md) == html + end + + fun test64 is test do + var md = """Foo\nBar\n---\n""" + var html = """

    Foo\nBar

    \n""" + assert md_to_html(md) == html + end + + fun test65 is test do + var md = """---\nFoo\n---\nBar\n---\nBaz\n""" + var html = """
    \n

    Foo

    \n

    Bar

    \n

    Baz

    \n""" + assert md_to_html(md) == html + end + + fun test66 is test do + var md = """\n====\n""" + var html = """

    ====

    \n""" + assert md_to_html(md) == html + end + + fun test67 is test do + var md = """---\n---\n""" + var html = """
    \n
    \n""" + assert md_to_html(md) == html + end + + fun test68 is test do + var md = """- foo\n-----\n""" + var html = """
      \n
    • foo
    • \n
    \n
    \n""" + assert md_to_html(md) == html + end + + fun test69 is test do + var md = """ foo\n---\n""" + var html = """
    foo\n
    \n
    \n""" + assert md_to_html(md) == html + end + + fun test70 is test do + var md = """> foo\n-----\n""" + var html = """
    \n

    foo

    \n
    \n
    \n""" + assert md_to_html(md) == html + end + + fun test71 is test do + var md = """\\> foo\n------\n""" + var html = """

    > foo

    \n""" + assert md_to_html(md) == html + end + + fun test72 is test do + var md = """Foo\n\nbar\n---\nbaz\n""" + var html = """

    Foo

    \n

    bar

    \n

    baz

    \n""" + assert md_to_html(md) == html + end + + fun test73 is test do + var md = """Foo\nbar\n\n---\n\nbaz\n""" + var html = """

    Foo\nbar

    \n
    \n

    baz

    \n""" + assert md_to_html(md) == html + end + + fun test74 is test do + var md = """Foo\nbar\n* * *\nbaz\n""" + var html = """

    Foo\nbar

    \n
    \n

    baz

    \n""" + assert md_to_html(md) == html + end + + fun test75 is test do + var md = """Foo\nbar\n\\---\nbaz\n""" + var html = """

    Foo\nbar\n---\nbaz

    \n""" + assert md_to_html(md) == html + end +end diff --git a/lib/markdown2/tests/test_commonmark_soft_line_breaks.nit b/lib/markdown2/tests/test_commonmark_soft_line_breaks.nit new file mode 100644 index 0000000..c3ce0f1 --- /dev/null +++ b/lib/markdown2/tests/test_commonmark_soft_line_breaks.nit @@ -0,0 +1,34 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module test_commonmark_soft_line_breaks is test + +import test_markdown + +class TestCommonmarkSoftLineBreaks + super TestMarkdownHtml + test + + fun test623 is test do + var md = """foo\nbaz\n""" + var html = """

    foo\nbaz

    \n""" + assert md_to_html(md) == html + end + + fun test624 is test do + var md = """foo \n baz\n""" + var html = """

    foo\nbaz

    \n""" + assert md_to_html(md) == html + end +end diff --git a/lib/markdown2/tests/test_commonmark_tabs.nit b/lib/markdown2/tests/test_commonmark_tabs.nit new file mode 100644 index 0000000..2a2f2ca --- /dev/null +++ b/lib/markdown2/tests/test_commonmark_tabs.nit @@ -0,0 +1,88 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module test_commonmark_tabs is test + +import test_markdown + +class TestCommonmarkTabs + super TestMarkdownHtml + test + + fun test1 is test do + var md = """\tfoo\tbaz\t\tbim\n""" + var html = """
    foo\tbaz\t\tbim\n
    \n""" + assert md_to_html(md) == html + end + + fun test2 is test do + var md = """ \tfoo\tbaz\t\tbim\n""" + var html = """
    foo\tbaz\t\tbim\n
    \n""" + assert md_to_html(md) == html + end + + fun test3 is test do + var md = """ a\ta\n ὐ\ta\n""" + var html = """
    a\ta\nὐ\ta\n
    \n""" + assert md_to_html(md) == html + end + + fun test4 is test do + var md = """ - foo\n\n\tbar\n""" + var html = """
      \n
    • \n

      foo

      \n

      bar

      \n
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test5 is test do + var md = """- foo\n\n\t\tbar\n""" + var html = """
      \n
    • \n

      foo

      \n
        bar\n
      \n
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test6 is test do + var md = """>\t\tfoo\n""" + var html = """
    \n
      foo\n
    \n
    \n""" + assert md_to_html(md) == html + end + + fun test7 is test do + var md = """-\t\tfoo\n""" + var html = """
      \n
    • \n
        foo\n
      \n
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test8 is test do + var md = """ foo\n\tbar\n""" + var html = """
    foo\nbar\n
    \n""" + assert md_to_html(md) == html + end + + fun test9 is test do + var md = """ - foo\n - bar\n\t - baz\n""" + var html = """
      \n
    • foo\n
        \n
      • bar\n
          \n
        • baz
        • \n
        \n
      • \n
      \n
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test10 is test do + var md = """#\tFoo\n""" + var html = """

    Foo

    \n""" + assert md_to_html(md) == html + end + + fun test11 is test do + var md = """*\t*\t*\t\n""" + var html = """
    \n""" + assert md_to_html(md) == html + end +end diff --git a/lib/markdown2/tests/test_commonmark_textual_content.nit b/lib/markdown2/tests/test_commonmark_textual_content.nit new file mode 100644 index 0000000..235e20e --- /dev/null +++ b/lib/markdown2/tests/test_commonmark_textual_content.nit @@ -0,0 +1,40 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module test_commonmark_textual_content is test + +import test_markdown + +class TestCommonmarkTextualContent + super TestMarkdownHtml + test + + fun test625 is test do + var md = """hello $.;'there\n""" + var html = """

    hello $.;'there

    \n""" + assert md_to_html(md) == html + end + + fun test626 is test do + var md = """Foo χρῆν\n""" + var html = """

    Foo χρῆν

    \n""" + assert md_to_html(md) == html + end + + fun test627 is test do + var md = """Multiple spaces\n""" + var html = """

    Multiple spaces

    \n""" + assert md_to_html(md) == html + end +end diff --git a/lib/markdown2/tests/test_commonmark_thematic_breaks.nit b/lib/markdown2/tests/test_commonmark_thematic_breaks.nit new file mode 100644 index 0000000..ae68fa4 --- /dev/null +++ b/lib/markdown2/tests/test_commonmark_thematic_breaks.nit @@ -0,0 +1,136 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module test_commonmark_thematic_breaks is test + +import test_markdown + +class TestCommonmarkThematicBreaks + super TestMarkdownHtml + test + + fun test13 is test do + var md = """***\n---\n___\n""" + var html = """
    \n
    \n
    \n""" + assert md_to_html(md) == html + end + + fun test14 is test do + var md = """+++\n""" + var html = """

    +++

    \n""" + assert md_to_html(md) == html + end + + fun test15 is test do + var md = """===\n""" + var html = """

    ===

    \n""" + assert md_to_html(md) == html + end + + fun test16 is test do + var md = """--\n**\n__\n""" + var html = """

    --\n**\n__

    \n""" + assert md_to_html(md) == html + end + + fun test17 is test do + var md = """ ***\n ***\n ***\n""" + var html = """
    \n
    \n
    \n""" + assert md_to_html(md) == html + end + + fun test18 is test do + var md = """ ***\n""" + var html = """
    ***\n
    \n""" + assert md_to_html(md) == html + end + + fun test19 is test do + var md = """Foo\n ***\n""" + var html = """

    Foo\n***

    \n""" + assert md_to_html(md) == html + end + + fun test20 is test do + var md = """_____________________________________\n""" + var html = """
    \n""" + assert md_to_html(md) == html + end + + fun test21 is test do + var md = """ - - -\n""" + var html = """
    \n""" + assert md_to_html(md) == html + end + + fun test22 is test do + var md = """ ** * ** * ** * **\n""" + var html = """
    \n""" + assert md_to_html(md) == html + end + + fun test23 is test do + var md = """- - - -\n""" + var html = """
    \n""" + assert md_to_html(md) == html + end + + fun test24 is test do + var md = """- - - - \n""" + var html = """
    \n""" + assert md_to_html(md) == html + end + + fun test25 is test do + var md = """_ _ _ _ a\n\na------\n\n---a---\n""" + var html = """

    _ _ _ _ a

    \n

    a------

    \n

    ---a---

    \n""" + assert md_to_html(md) == html + end + + fun test26 is test do + var md = """ *-*\n""" + var html = """

    -

    \n""" + assert md_to_html(md) == html + end + + fun test27 is test do + var md = """- foo\n***\n- bar\n""" + var html = """
      \n
    • foo
    • \n
    \n
    \n
      \n
    • bar
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test28 is test do + var md = """Foo\n***\nbar\n""" + var html = """

    Foo

    \n
    \n

    bar

    \n""" + assert md_to_html(md) == html + end + + fun test29 is test do + var md = """Foo\n---\nbar\n""" + var html = """

    Foo

    \n

    bar

    \n""" + assert md_to_html(md) == html + end + + fun test30 is test do + var md = """* Foo\n* * *\n* Bar\n""" + var html = """
      \n
    • Foo
    • \n
    \n
    \n
      \n
    • Bar
    • \n
    \n""" + assert md_to_html(md) == html + end + + fun test31 is test do + var md = """- Foo\n- * * *\n""" + var html = """
      \n
    • Foo
    • \n
    • \n
      \n
    • \n
    \n""" + assert md_to_html(md) == html + end +end diff --git a/lib/markdown2/tests/test_markdown.nit b/lib/markdown2/tests/test_markdown.nit new file mode 100644 index 0000000..60f1f34 --- /dev/null +++ b/lib/markdown2/tests/test_markdown.nit @@ -0,0 +1,42 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Test suites for module `markdown` +module test_markdown + +import markdown_html_rendering + +# Abstract test class that instanciates the markdown parser +abstract class TestMarkdown + + # Markdown parser to use in tests + var md_parser = new MdParser + + # Parse a `md` string as a MdNode + fun parse_md(md: String): MdNode do return md_parser.parse(md) +end + +# Abstract test class that defines the test methods for HTML rendering +abstract class TestMarkdownHtml + super TestMarkdown + + # HTML renderer used in tests + var html_renderer = new HtmlRenderer + + # Render the `md` string as HTML + fun md_to_html(md: String): String do + var node = parse_md(md) + return html_renderer.render(node) + end +end diff --git a/lib/markdown2/tests/test_markdown_blocks.nit b/lib/markdown2/tests/test_markdown_blocks.nit new file mode 100644 index 0000000..f81d225 --- /dev/null +++ b/lib/markdown2/tests/test_markdown_blocks.nit @@ -0,0 +1,660 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either htmlress or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Test for markdown blocks parsing +module test_markdown_blocks is test + +import test_markdown + +class TestMarkdownBlocks + super TestMarkdownHtml + test + + fun test_blocks_empty is test do + var md = "" + var html = "" + assert md_to_html(md) == html + end + + fun test_blocks_tabs is test do + var md = """\tsome code\n""" + var html = """
    some code\n
    \n""" + assert md_to_html(md) == html + end + + fun test_blocks_pagraph1 is test do + var md = "test\n" + var html = "

    test

    \n" + assert md_to_html(md) == html + end + + fun test_blocks_pagraph2 is test do + var md = """line1\nline2\n\nline3 line4\n\nline5\n""" + var html = """

    line1\nline2

    \n

    line3 line4

    \n

    line5

    \n""" + assert md_to_html(md) == html + end + + fun test_blocks_pagraph3 is test do + var md = """ +Lorem ipsum dolor sit amet, consectetuer adipiscing elit. +Aliquam hendrerit mi posuere lectus. +Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus. + +Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse +id sem consectetuer libero luctus adipiscing. +""" + var html = """ +

    Lorem ipsum dolor sit amet, consectetuer adipiscing elit. +Aliquam hendrerit mi posuere lectus. +Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.

    +

    Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse +id sem consectetuer libero luctus adipiscing.

    +""" + assert md_to_html(md) == html + end + + fun test_blocks_headings_1 is test do + var md = """ +This is a H1 +============= + +This is a H2 +------------- +""" + var html = """ +

    This is a H1

    +

    This is a H2

    +""" + assert md_to_html(md) == html + end + + fun test_blocks_headings_2 is test do + var md = """ +# This is a H1 + +## This is a H2 +###### This is a H6 +""" + var html = """ +

    This is a H1

    +

    This is a H2

    +
    This is a H6
    +""" + assert md_to_html(md) == html + end + + fun test_blocks_headings_3 is test do + var md = """ +# This is a H1 # + +## This is a H2 ## + +### This is a H3 ###### +""" + var html = """ +

    This is a H1

    +

    This is a H2

    +

    This is a H3

    +""" + assert md_to_html(md) == html + end + + fun test_blocks_hr1 is test do + var md = """ +* * * + +*** + +***** + +- - - + +--------------------------------------- +""" + var html = "
    \n
    \n
    \n
    \n
    \n" + assert md_to_html(md) == html + end + + fun test_blocks_bquote1 is test do + var md = """ +> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet, +> consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. +> Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus. +> +> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse +> id sem consectetuer libero luctus adipiscing. +""" + var html = """
    +

    This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet, +consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. +Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.

    +

    Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse +id sem consectetuer libero luctus adipiscing.

    +
    +""" + assert md_to_html(md) == html + end + + fun test_blocks_bquote2 is test do + var md = """ +> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet, +consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. +Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus. + +> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse +id sem consectetuer libero luctus adipiscing. +""" + var html = """
    +

    This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet, +consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. +Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.

    +
    +
    +

    Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse +id sem consectetuer libero luctus adipiscing.

    +
    +""" + assert md_to_html(md) == html + end + + fun test_blocks_bquote3 is test do + var md = """ +> This is the first level of quoting. +> +> > This is nested blockquote. +> +> Back to the first level. +""" + var html = """
    +

    This is the first level of quoting.

    +
    +

    This is nested blockquote.

    +
    +

    Back to the first level.

    +
    +""" + assert md_to_html(md) == html + end + + fun test_blocks_list1 is test do + var md = """ +* Red +* Green +* Blue +""" + var html = """
      +
    • Red
    • +
    • Green
    • +
    • Blue
    • +
    +""" + assert md_to_html(md) == html + end + + fun test_blocks_list2 is test do + var md = """ ++ Red ++ Green ++ Blue +""" + var html = """
      +
    • Red
    • +
    • Green
    • +
    • Blue
    • +
    +""" + assert md_to_html(md) == html + end + + fun test_blocks_list3 is test do + var md = """ +- Red +- Green +- Blue +""" + var html = """
      +
    • Red
    • +
    • Green
    • +
    • Blue
    • +
    +""" + assert md_to_html(md) == html + end + + fun test_blocks_list4 is test do + var md = """ +1. Bird +2. McHale +3. Parish +""" + var html = """
      +
    1. Bird
    2. +
    3. McHale
    4. +
    5. Parish
    6. +
    +""" + assert md_to_html(md) == html + end + + fun test_blocks_list5 is test do + var md = """ +3. Bird +1. McHale +8. Parish +""" + var html = """
      +
    1. Bird
    2. +
    3. McHale
    4. +
    5. Parish
    6. +
    +""" + assert md_to_html(md) == html + end + + fun test_blocks_list6 is test do + var md = """ +* Lorem ipsum dolor sit amet, consectetuer adipiscing elit. + Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi, + viverra nec, fringilla in, laoreet vitae, risus. +* Donec sit amet nisl. Aliquam semper ipsum sit amet velit. + Suspendisse id sem consectetuer libero luctus adipiscing. +""" + var html = """ +
      +
    • Lorem ipsum dolor sit amet, consectetuer adipiscing elit. +Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi, +viverra nec, fringilla in, laoreet vitae, risus.
    • +
    • Donec sit amet nisl. Aliquam semper ipsum sit amet velit. +Suspendisse id sem consectetuer libero luctus adipiscing.
    • +
    +""" + assert md_to_html(md) == html + end + + fun test_blocks_list7 is test do + var md = """ +* Lorem ipsum dolor sit amet, consectetuer adipiscing elit. +Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi, +viverra nec, fringilla in, laoreet vitae, risus. +* Donec sit amet nisl. Aliquam semper ipsum sit amet velit. +Suspendisse id sem consectetuer libero luctus adipiscing. +""" + var html = """ +
      +
    • Lorem ipsum dolor sit amet, consectetuer adipiscing elit. +Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi, +viverra nec, fringilla in, laoreet vitae, risus.
    • +
    • Donec sit amet nisl. Aliquam semper ipsum sit amet velit. +Suspendisse id sem consectetuer libero luctus adipiscing.
    • +
    +""" + assert md_to_html(md) == html + end + + fun test_blocks_list8 is test do + var md = """ +* Bird + +* Magic +""" + var html = """ +
      +
    • +

      Bird

      +
    • +
    • +

      Magic

      +
    • +
    +""" + assert md_to_html(md) == html + end + + fun test_blocks_list9 is test do + var md = """ +1. This is a list item with two paragraphs. Lorem ipsum dolor + sit amet, consectetuer adipiscing elit. Aliquam hendrerit + mi posuere lectus. + + Vestibulum enim wisi, viverra nec, fringilla in, laoreet + vitae, risus. Donec sit amet nisl. Aliquam semper ipsum + sit amet velit. + +2. Suspendisse id sem consectetuer libero luctus adipiscing. +""" + var html = """ +
      +
    1. +

      This is a list item with two paragraphs. Lorem ipsum dolor +sit amet, consectetuer adipiscing elit. Aliquam hendrerit +mi posuere lectus.

      +

      Vestibulum enim wisi, viverra nec, fringilla in, laoreet +vitae, risus. Donec sit amet nisl. Aliquam semper ipsum +sit amet velit.

      +
    2. +
    3. +

      Suspendisse id sem consectetuer libero luctus adipiscing.

      +
    4. +
    +""" + assert md_to_html(md) == html + end + + fun test_blocks_list10 is test do + var md = """ +* This is a list item with two paragraphs. + + This is the second paragraph in the list item. You're +only required to indent the first line. Lorem ipsum dolor +sit amet, consectetuer adipiscing elit. + +* Another item in the same list. +""" + var html = """ +
      +
    • +

      This is a list item with two paragraphs.

      +

      This is the second paragraph in the list item. You're +only required to indent the first line. Lorem ipsum dolor +sit amet, consectetuer adipiscing elit.

      +
    • +
    • +

      Another item in the same list.

      +
    • +
    +""" + assert md_to_html(md) == html + end + + fun test_blocks_list_ext is test do + var md = """ +This is a paragraph +* and this is a list +""" + var html = """ +

    This is a paragraph

    +
      +
    • and this is a list
    • +
    +""" + assert md_to_html(md) == html + end + + fun test_blocks_indented_code1 is test do + var md = """ +This is a normal paragraph: + + This is a code block. +""" + var html = """

    This is a normal paragraph:

    +
    This is a code block.
    +
    +""" + assert md_to_html(md) == html + end + + fun test_blocks_indented_code2 is test do + var md = """ +Here is an example of AppleScript: + + tell application "Foo" + beep + end tell + + +""" + var html = """ +

    Here is an example of AppleScript:

    +
    tell application "Foo"
    +    beep
    +end tell
    +
    +<div class="footer">
    +    &copy; 2004 Foo Corporation
    +</div>
    +
    +""" + assert md_to_html(md) == html + end + + fun test_blocks_indented_code3 is test do + var md = """ +Here is an example of AppleScript: + + beep +""" + var html = """ +

    Here is an example of AppleScript:

    +
    beep
    +
    +""" + assert md_to_html(md) == html + end + + fun test_blocks_fenced_code1 is test do + var md = """ +Here is an example of AppleScript: +~~~ +tell application "Foo" + beep +end tell + + +~~~ +""" + var html = """ +

    Here is an example of AppleScript:

    +
    tell application "Foo"
    +    beep
    +end tell
    +
    +<div class="footer">
    +    &copy; 2004 Foo Corporation
    +</div>
    +
    +""" + assert md_to_html(md) == html + end + + fun test_blocks_fenced_code2 is test do + var md = """ +Here is an example of AppleScript: +``` +tell application "Foo" + beep +end tell + + +``` +""" + var html = """ +

    Here is an example of AppleScript:

    +
    tell application "Foo"
    +    beep
    +end tell
    +
    +<div class="footer">
    +    &copy; 2004 Foo Corporation
    +</div>
    +
    +""" + assert md_to_html(md) == html + end + + fun test_blocks_fenced_code3 is test do + var md = """ +```nit +print "Hello World!" +``` +""" + var html = """ +
    print "Hello World!"
    +
    +""" + assert md_to_html(md) == html + end + + fun test_blocks_fenced_code4 is test do + var md = """ +~~~ +print "Hello" +~~~ +~~~ +print "World" +~~~ +""" + var html = """ +
    print "Hello"
    +
    +
    print "World"
    +
    +""" + assert md_to_html(md) == html + end + + fun test_blocks_fenced_code5 is test do + var md = """ +~~~ +print "Hello" +~~~ +~~~ +print "World" +~~~ +""" + var html = """ +
    print "Hello"
    +
    +
    print "World"
    +
    +""" + assert md_to_html(md) == html + end + + fun test_blocks_nesting1 is test do + var md = """ +> ## This is a header. +> +> 1. This is the first list item. +> 2. This is the second list item. +> +> Here's some example code: +> +> return shell_exec("echo $input | $markdown_script"); +""" + var html = """ +
    +

    This is a header.

    +
      +
    1. This is the first list item.
    2. +
    3. This is the second list item.
    4. +
    +

    Here's some example code:

    +
    return shell_exec("echo $input | $markdown_script");
    +
    +
    +""" + assert md_to_html(md) == html + end + + fun test_blocks_nesting2 is test do + var md = """ +* A list item with a blockquote: + + > This is a blockquote + > inside a list item. +""" + var html = """ +
      +
    • +

      A list item with a blockquote:

      +
      +

      This is a blockquote +inside a list item.

      +
      +
    • +
    +""" + assert md_to_html(md) == html + end + + fun test_blocks_nesting3 is test do + var md = """ +* A list item with a code block: + + +""" + var html = """ +
      +
    • +

      A list item with a code block:

      +
      <code goes here>
      +
      +
    • +
    +""" + assert md_to_html(md) == html + end + + fun test_blocks_nesting4 is test do + var md = """ +* Tab + * Tab + * Tab +""" + var html = """ +
      +
    • Tab +
        +
      • Tab +
          +
        • Tab
        • +
        +
      • +
      +
    • +
    +""" + assert md_to_html(md) == html + end + + fun test_blocks_nesting5 is test do + var md = """ +* this + + * sub + + that +""" + var html = """ +
      +
    • +

      this

      +
        +
      • +

        sub

        +

        that

        +
      • +
      +
    • +
    +""" + assert md_to_html(md) == html + end +end diff --git a/lib/markdown2/tests/test_markdown_daring.nit b/lib/markdown2/tests/test_markdown_daring.nit new file mode 100644 index 0000000..962e356 --- /dev/null +++ b/lib/markdown2/tests/test_markdown_daring.nit @@ -0,0 +1,1343 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either htmlress or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Markdown tests from DaringFireball +# +# See . +module test_markdown_daring is test + +import test_markdown + +class TestMarkdownDaring + super TestMarkdownHtml + test + + fun test_daring_encoding is test do + var md = """ +AT&T has an ampersand in their name. + +AT&T is another way to write it. + +This & that. + +4 < 5. + +6 > 5. + +Here's a [link][1] with an ampersand in the URL. + +Here's a link with an ampersand in the link text: [AT&T][2]. + +Here's an inline [link](/script?foo=1&bar=2). + +Here's an inline [link](). + + +[1]: http://example.com/?foo=1&bar=2 +[2]: http://att.com/ "AT&T" +""" + + var html = """ +

    AT&T has an ampersand in their name.

    +

    AT&T is another way to write it.

    +

    This & that.

    +

    4 < 5.

    +

    6 > 5.

    +

    Here's a link with an ampersand in the URL.

    +

    Here's a link with an ampersand in the link text: AT&T.

    +

    Here's an inline link.

    +

    Here's an inline link.

    +""" + assert md_to_html(md) == html + end + + fun test_daring_autolinks is test do + var md = """ +Link: . + +With an ampersand: + +* In a list? +* +* It should. + +> Blockquoted: + +Auto-links should not occur here: `` + + or here: +""" + + var html = """ +

    Link: http://example.com/.

    +

    With an ampersand: http://example.com/?foo=1&bar=2

    + +
    +

    Blockquoted: http://example.com/

    +
    +

    Auto-links should not occur here: <http://example.com/>

    +
    or here: <http://example.com/>
    +
    +""" + assert md_to_html(md) == html + end + + fun test_daring_escape is test do + var md = """ +These should all get escaped: + +Backslash: \\ + +Backtick: \` + +Asterisk: \* + +Underscore: \_ + +Left brace: \{ + +Right brace: \} + +Left bracket: \[ + +Right bracket: \] + +Left paren: \( + +Right paren: \) + +Greater-than: \> + +Hash: \# + +Period: \. + +Bang: \! + +Plus: \+ + +Minus: \- + + +These should not, because they occur within a code block: + + Backslash: \\ + + Backtick: \` + + Asterisk: \* + + Underscore: \_ + + Left brace: \{ + + Right brace: \} + + Left bracket: \[ + + Right bracket: \] + + Left paren: \( + + Right paren: \) + + Greater-than: \> + + Hash: \# + + Period: \. + + Bang: \! + + Plus: \+ + + Minus: \- + +Nor should these, which occur in code spans: + +Backslash: `\\` + +Backtick: `` \` `` + +Asterisk: `\*` + +Underscore: `\_` + +Left brace: `\{` + +Right brace: `\}` + +Left bracket: `\[` + +Right bracket: `\]` + +Left paren: `\(` + +Right paren: `\)` + +Greater-than: `\>` + +Hash: `\#` + +Period: `\.` + +Bang: `\!` + +Plus: `\+` + +Minus: `\-` + +These should get escaped, even though they're matching pairs for +other Markdown constructs: + +\\\*asterisks\\\* + +\\\_underscores\\\_ + +\\\`backticks\\\` + +This is a code span with a literal backslash-backtick sequence: `` \` `` + +This is a tag with unescaped backticks bar. + +This is a tag with backslashes bar. +""" + var html = """ +

    These should all get escaped:

    +

    Backslash: \\

    +

    Backtick: \`

    +

    Asterisk: \*

    +

    Underscore: \_

    +

    Left brace: \{

    +

    Right brace: \}

    +

    Left bracket: \[

    +

    Right bracket: \]

    +

    Left paren: \(

    +

    Right paren: \)

    +

    Greater-than: >

    +

    Hash: \#

    +

    Period: \.

    +

    Bang: \!

    +

    Plus: \+

    +

    Minus: \-

    +

    These should not, because they occur within a code block:

    +
    Backslash: \\
    +
    +Backtick: \`
    +
    +Asterisk: \*
    +
    +Underscore: \_
    +
    +Left brace: \{
    +
    +Right brace: \}
    +
    +Left bracket: \[
    +
    +Right bracket: \]
    +
    +Left paren: \(
    +
    +Right paren: \)
    +
    +Greater-than: \>
    +
    +Hash: \#
    +
    +Period: \.
    +
    +Bang: \!
    +
    +Plus: \+
    +
    +Minus: \-
    +
    +

    Nor should these, which occur in code spans:

    +

    Backslash: \\

    +

    Backtick: \`

    +

    Asterisk: \*

    +

    Underscore: \_

    +

    Left brace: \{

    +

    Right brace: \}

    +

    Left bracket: \[

    +

    Right bracket: \]

    +

    Left paren: \(

    +

    Right paren: \)

    +

    Greater-than: \>

    +

    Hash: \#

    +

    Period: \.

    +

    Bang: \!

    +

    Plus: \+

    +

    Minus: \-

    +

    These should get escaped, even though they're matching pairs for +other Markdown constructs:

    +

    *asterisks*

    +

    _underscores_

    +

    `backticks`

    +

    This is a code span with a literal backslash-backtick sequence: \`

    +

    This is a tag with unescaped backticks bar.

    +

    This is a tag with backslashes bar.

    +""" + + assert md_to_html(md) == html + end + + fun test_daring_blockquotes is test do + var md = """ +> Example: +> +> sub status { +> print "working"; +> } +> +> Or: +> +> sub status { +> return "working"; +> } +""" + + var html = """ +
    +

    Example:

    +
    sub status {
    +    print "working";
    +}
    +
    +

    Or:

    +
    sub status {
    +    return "working";
    +}
    +
    +
    +""" + assert md_to_html(md) == html + end + + fun test_daring_code_blocks is test do + var md = """ + code block on the first line + +Regular text. + + code block indented by spaces + +Regular text. + + the lines in this block + all contain trailing spaces + +Regular Text. + + code block on the last line +""" + + var html = """ +
    code block on the first line
    +
    +

    Regular text.

    +
    code block indented by spaces
    +
    +

    Regular text.

    +
    the lines in this block
    +all contain trailing spaces
    +
    +

    Regular Text.

    +
    code block on the last line
    +
    +""" + assert md_to_html(md) == html + end + + fun test_daring_rules is test do + var md = """ +Dashes: + +--- + + --- + + --- + + --- + + --- + +- - - + + - - - + + - - - + + - - - + + - - - + + +Asterisks: + +*** + + *** + + *** + + *** + + *** + +* * * + + * * * + + * * * + + * * * + + * * * + + +Underscores: + +___ + + ___ + + ___ + + ___ + + ___ + +_ _ _ + + _ _ _ + + _ _ _ + + _ _ _ + + _ _ _ +""" + + var html = """ +

    Dashes:

    +
    +
    +
    +
    +
    ---
    +
    +
    +
    +
    +
    +
    - - -
    +
    +

    Asterisks:

    +
    +
    +
    +
    +
    ***
    +
    +
    +
    +
    +
    +
    * * *
    +
    +

    Underscores:

    +
    +
    +
    +
    +
    ___
    +
    +
    +
    +
    +
    +
    _ _ _
    +
    +""" + assert md_to_html(md) == html + end + + fun test_daring_code_spans is test do + var md = """ +`` + +Fix for backticks within HTML tag: like this + +Here's how you put `` `backticks` `` in a code span. +""" + + var html = """ +

    <test a=" content of attribute ">

    +

    Fix for backticks within HTML tag: like this

    +

    Here's how you put `backticks` in a code span.

    +""" + assert md_to_html(md) == html + end + + fun test_daring_images is test do + var md = """ +![Alt text](/path/to/img.jpg) + +![Alt text](/path/to/img.jpg "Optional title") + +Inline within a paragraph: [alt text](/url/). + +![alt text](/url/ "title preceded by two spaces") + +![alt text](/url/ "title has spaces afterward" ) + +![alt text]() + +![alt text]( "with a title"). + +![Empty]() + +![this is a stupid URL](http://example.com/(parens).jpg) + + +![alt text][foo] + + [foo]: /url/ + +![alt text][bar] + + [bar]: /url/ "Title here" +""" + + var html = """ +

    Alt text

    +

    Alt text

    +

    Inline within a paragraph: alt text.

    +

    alt text

    +

    alt text

    +

    alt text

    +

    alt text.

    +

    Empty

    +

    this is a stupid URL

    +

    alt text

    +

    alt text

    +""" + assert md_to_html(md) == html + end + + fun test_daring_links1 is test do + var md = """ +Just a [URL](/url/). + +[URL and title](/url/ "title"). + +[URL and title](/url/ "title preceded by two spaces"). + +[URL and title](/url/ "title preceded by a tab"). + +[URL and title](/url/ "title has spaces afterward" ). + +[URL wrapped in angle brackets](). + +[URL w/ angle brackets + title]( "Here's the title"). + +[Empty](). + +[With parens in the URL](http://en.wikipedia.org/wiki/WIMP_(computing)) + +(With outer parens and [parens in url](/foo(bar))) + + +[With parens in the URL](/foo(bar) "and a title") + +(With outer parens and [parens in url](/foo(bar) "and a title")) +""" + + var html = """ +

    Just a URL.

    +

    URL and title.

    +

    URL and title.

    +

    URL and title.

    +

    URL and title.

    +

    URL wrapped in angle brackets.

    +

    URL w/ angle brackets + title.

    +

    Empty.

    +

    With parens in the URL

    +

    (With outer parens and parens in url)

    +

    With parens in the URL

    +

    (With outer parens and parens in url)

    +""" + assert md_to_html(md) == html + end + + fun test_daring_links2 is test do + var md = """ +Foo [bar][1]. + + Foo [bar][1]. + + Foo [bar][1]. + +[1]: /url/ "Title" + + +With [embedded [brackets]][b]. + + + Indented [once][]. + + Indented [twice][]. + + Indented [thrice][]. + + Indented [four][] times. + + [once]: /url + + [twice]: /url + + [thrice]: /url + + [four]: /url + + +[b]: /url/ + +* * * + +[this][this] should work + +So should [this][this]. + +And [this][]. + +And [this][]. + +And [this]. + +But not [that][]. + +Nor [that][]. + +Nor [that]. + +[Something in brackets like [this][] should work] + +[Same with [this].] + +In this case, [this](/somethingelse/) points to something else. + +Backslashing should suppress \\\[this] and [this\\\]. + +[this]: foo + + +* * * + +Here's one where the [link +breaks] across lines. + +Here's another where the [link +breaks] across lines, but with a line-ending space. + + +[link breaks]: /url/ +""" + + var html = """ +

    Foo bar.

    +

    Foo bar.

    +

    Foo bar.

    +

    With embedded [brackets].

    +

    Indented once.

    +

    Indented twice.

    +

    Indented thrice.

    +
    Indented [four][] times.
    +
    +
    [four]: /url
    +
    +
    +

    this should work

    +

    So should this.

    +

    And this.

    +

    And this.

    +

    And this.

    +

    But not [that][].

    +

    Nor [that][].

    +

    Nor [that].

    +

    [Something in brackets like this should work]

    +

    [Same with this.]

    +

    In this case, this points to something else.

    +

    Backslashing should suppress [this] and [this].

    +
    +

    Here's one where the link +breaks across lines.

    +

    Here's another where the link +breaks across lines, but with a line-ending space.

    +""" + assert md_to_html(md) == html + end + + fun test_daring_links3 is test do + var md = """ +This is the [simple case]. + +[simple case]: /simple + + + +This one has a [line +break]. + +This one has a [line +break] with a line-ending space. + +[line break]: /foo + + +[this][that] and the [other] + +[this]: /this +[that]: /that +[other]: /other +""" + + var html = """ +

    This is the simple case.

    +

    This one has a line +break.

    +

    This one has a line +break with a line-ending space.

    +

    this and the other

    +""" + assert md_to_html(md) == html + end + + fun test_daring_nested is test do + var md = """ +> foo +> +> > bar +> +> foo +""" + + var html = """ +
    +

    foo

    +
    +

    bar

    +
    +

    foo

    +
    +""" + assert md_to_html(md) == html + end + + fun test_daring_tidyness is test do + var md = """ +> A list within a blockquote: +> +> * asterisk 1 +> * asterisk 2 +> * asterisk 3 +""" + + var html = """ +
    +

    A list within a blockquote:

    +
      +
    • asterisk 1
    • +
    • asterisk 2
    • +
    • asterisk 3
    • +
    +
    +""" + assert md_to_html(md) == html + end + + fun test_daring_list is test do + var md = """ +## Unordered + +Asterisks tight: + +* asterisk 1 +* asterisk 2 +* asterisk 3 + + +Asterisks loose: + +* asterisk 1 + +* asterisk 2 + +* asterisk 3 + +* * * + +Pluses tight: + ++ Plus 1 ++ Plus 2 ++ Plus 3 + + +Pluses loose: + ++ Plus 1 + ++ Plus 2 + ++ Plus 3 + +* * * + + +Minuses tight: + +- Minus 1 +- Minus 2 +- Minus 3 + + +Minuses loose: + +- Minus 1 + +- Minus 2 + +- Minus 3 + + +## Ordered + +Tight: + +1. First +2. Second +3. Third + +and: + +1. One +2. Two +3. Three + + +Loose using tabs: + +1. First + +2. Second + +3. Third + +and using spaces: + +1. One + +2. Two + +3. Three + +Multiple paragraphs: + +1. Item 1, graf one. + + Item 2. graf two. The quick brown fox jumped over the lazy dog's + back. + +2. Item 2. + +3. Item 3. + + + +## Nested + +* Tab + * Tab + * Tab + +Here's another: + +1. First +2. Second: + * Fee + * Fie + * Foe +3. Third + +Same thing but with paragraphs: + +1. First + +2. Second: + * Fee + * Fie + * Foe + +3. Third +""" + + var html = """ +

    Unordered

    +

    Asterisks tight:

    +
      +
    • asterisk 1
    • +
    • asterisk 2
    • +
    • asterisk 3
    • +
    +

    Asterisks loose:

    +
      +
    • +

      asterisk 1

      +
    • +
    • +

      asterisk 2

      +
    • +
    • +

      asterisk 3

      +
    • +
    +
    +

    Pluses tight:

    +
      +
    • Plus 1
    • +
    • Plus 2
    • +
    • Plus 3
    • +
    +

    Pluses loose:

    +
      +
    • +

      Plus 1

      +
    • +
    • +

      Plus 2

      +
    • +
    • +

      Plus 3

      +
    • +
    +
    +

    Minuses tight:

    +
      +
    • Minus 1
    • +
    • Minus 2
    • +
    • Minus 3
    • +
    +

    Minuses loose:

    +
      +
    • +

      Minus 1

      +
    • +
    • +

      Minus 2

      +
    • +
    • +

      Minus 3

      +
    • +
    +

    Ordered

    +

    Tight:

    +
      +
    1. First
    2. +
    3. Second
    4. +
    5. Third
    6. +
    +

    and:

    +
      +
    1. One
    2. +
    3. Two
    4. +
    5. Three
    6. +
    +

    Loose using tabs:

    +
      +
    1. +

      First

      +
    2. +
    3. +

      Second

      +
    4. +
    5. +

      Third

      +
    6. +
    +

    and using spaces:

    +
      +
    1. +

      One

      +
    2. +
    3. +

      Two

      +
    4. +
    5. +

      Three

      +
    6. +
    +

    Multiple paragraphs:

    +
      +
    1. +

      Item 1, graf one.

      +

      Item 2. graf two. The quick brown fox jumped over the lazy dog's +back.

      +
    2. +
    3. +

      Item 2.

      +
    4. +
    5. +

      Item 3.

      +
    6. +
    +

    Nested

    +
      +
    • Tab +
        +
      • Tab +
          +
        • Tab
        • +
        +
      • +
      +
    • +
    +

    Here's another:

    +
      +
    1. First
    2. +
    3. Second: +
        +
      • Fee
      • +
      • Fie
      • +
      • Foe
      • +
      +
    4. +
    5. Third
    6. +
    +

    Same thing but with paragraphs:

    +
      +
    1. +

      First

      +
    2. +
    3. +

      Second:

      +
        +
      • Fee
      • +
      • Fie
      • +
      • Foe
      • +
      +
    4. +
    5. +

      Third

      +
    6. +
    +""" + assert md_to_html(md) == html + end + + fun test_daring_strong_em is test do + var md = """ +***This is strong and em.*** + +So is ***this*** word. + +___This is strong and em.___ + +So is ___this___ word. +""" + + var html = """ +

    This is strong and em.

    +

    So is this word.

    +

    This is strong and em.

    +

    So is this word.

    +""" + assert md_to_html(md) == html + end + + fun test_daring_tabs is test do + var md = """ ++ this is a list item + indented with tabs + ++ this is a list item + indented with spaces + +Code: + + this code block is indented by one tab + +And: + + this code block is indented by two tabs + +And: + + + this is an example list item + indented with tabs + + + this is an example list item + indented with spaces +""" + + var html = """ +
      +
    • +

      this is a list item +indented with tabs

      +
    • +
    • +

      this is a list item +indented with spaces

      +
    • +
    +

    Code:

    +
    this code block is indented by one tab
    +
    +

    And:

    +
    	this code block is indented by two tabs
    +
    +

    And:

    +
    +	this is an example list item
    +	indented with tabs
    +
    ++   this is an example list item
    +    indented with spaces
    +
    +""" + assert md_to_html(md) == html + end + + fun test_daring_inline_html1 is test do + var md = """ +Here's a simple block: + +
    + foo +
    + +This should be a code block, though: + +
    + foo +
    + +As should this: + +
    foo
    + +Now, nested: + +
    +
    +
    + foo +
    +
    +
    + +This should just be an HTML comment: + + + +Multiline: + + + +Code block: + + + +Just plain comment, with trailing spaces on the line: + + + +Code: + +
    + +Hr's: + +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    +""" + + var html = """ +

    Here's a simple block:

    +
    + foo +
    +

    This should be a code block, though:

    +
    <div>
    +	foo
    +</div>
    +
    +

    As should this:

    +
    <div>foo</div>
    +
    +

    Now, nested:

    +
    +
    +
    + foo +
    +
    +
    +

    This should just be an HTML comment:

    + +

    Multiline:

    + +

    Code block:

    +
    <!-- Comment -->
    +
    +

    Just plain comment, with trailing spaces on the line:

    + +

    Code:

    +
    <hr />
    +
    +

    Hr's:

    +
    +
    +
    +
    +
    +
    +
    +
    +
    +""" + assert md_to_html(md) == html + end + + fun test_daring_inline_html2 is test do + var md = """ +Simple block on one line: + +
    foo
    + +And nested without indentation: + +
    +
    +
    +foo +
    +
    +
    +
    bar
    +
    + +And with attributes: + +
    +
    +
    +
    + +This was broken in 1.0.2b7: + +
    +
    +foo +
    +
    +""" + + var html = """ +

    Simple block on one line:

    +
    foo
    +

    And nested without indentation:

    +
    +
    +
    +foo +
    +
    +
    +
    bar
    +
    +

    And with attributes:

    +
    +
    +
    +
    +

    This was broken in 1.0.2b7:

    +
    +
    +foo +
    +
    +""" + assert md_to_html(md) == html + end + + fun test_daring_inline_html3 is test do + var md = """ +Paragraph one. + + + + + +Paragraph two. + + + +The end. +""" + + var html = """ +

    Paragraph one.

    + + +

    Paragraph two.

    + +

    The end.

    +""" + assert md_to_html(md) == html + end +end diff --git a/lib/markdown2/tests/test_markdown_github.nit b/lib/markdown2/tests/test_markdown_github.nit new file mode 100644 index 0000000..04c04a4 --- /dev/null +++ b/lib/markdown2/tests/test_markdown_github.nit @@ -0,0 +1,313 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Tests for markdown Github mode +module test_markdown_github is test + +import test_markdown +import test_markdown_location +import test_markdown_md +import test_markdown_man +import test_markdown_latex + +redef class TestMarkdown + redef var md_parser is lazy do + var parser = super + parser.github_mode = true + return parser + end +end + +class TestGithubLocation + super TestMarkdownLocation + test + + fun test_github_strike is test do + var md = """ +A ~striked~ text. +""" + var loc = """ +MdDocument: 1,1--1,17 + MdParagraph: 1,1--1,17 + MdText: 1,1--1,2 + MdStrike: 1,3--1,11 + MdText: 1,4--1,10 + MdText: 1,12--1,17 +""" + assert md_to_loc(md) == loc + end + + fun test_github_strike2 is test do + var md = """ +A ~~striked~~ text. +""" + var loc = """ +MdDocument: 1,1--1,19 + MdParagraph: 1,1--1,19 + MdText: 1,1--1,2 + MdStrike: 1,3--1,13 + MdText: 1,5--1,11 + MdText: 1,14--1,19 +""" + assert md_to_loc(md) == loc + end + + fun test_github_super is test do + var md = """ +A ^supered^ text. +""" + var loc = """ +MdDocument: 1,1--1,17 + MdParagraph: 1,1--1,17 + MdText: 1,1--1,2 + MdSuper: 1,3--1,11 + MdText: 1,4--1,10 + MdText: 1,12--1,17 +""" + assert md_to_loc(md) == loc + end + + fun test_github_super2 is test do + var md = """ +A ^^supered^^ text. +""" + var loc = """ +MdDocument: 1,1--1,19 + MdParagraph: 1,1--1,19 + MdText: 1,1--1,2 + MdSuper: 1,3--1,13 + MdText: 1,5--1,11 + MdText: 1,14--1,19 +""" + assert md_to_loc(md) == loc + end +end + +class TestGithubHtml + super TestMarkdownHtml + test + + fun test_strike1 is test do + var md = """foo ~bar~ baz\n""" + var html = """

    foo bar baz

    \n""" + assert md_to_html(md) == html + end + + fun test_strike2 is test do + var md = """foo ~~bar~~ baz\n""" + var html = """

    foo bar baz

    \n""" + assert md_to_html(md) == html + end + + fun test_strike3 is test do + var md = """foo ~~~bar~~~ baz\n""" + var html = """

    foo bar baz

    \n""" + assert md_to_html(md) == html + end + + fun test_strike4 is test do + var md = """foo ~~~~bar~~~~ baz\n""" + var html = """

    foo bar baz

    \n""" + assert md_to_html(md) == html + end + + fun test_strike5 is test do + var md = """foo ~~~~~bar~~~~~ baz\n""" + var html = """

    foo bar baz

    \n""" + assert md_to_html(md) == html + end + + fun test_strike6 is test do + var md = """foo ~~~~~~bar~~~~~~ baz\n""" + var html = """

    foo bar baz

    \n""" + assert md_to_html(md) == html + end + + fun test_strike_bad is test do + var md = """foo ~bar baz\n""" + var html = """

    foo ~bar baz

    \n""" + assert md_to_html(md) == html + end + + fun test_strike_bad2 is test do + var md = """foo ~~bar~ baz\n""" + var html = """

    foo bar baz

    \n""" + assert md_to_html(md) == html + end + + fun test_strike_bad3 is test do + var md = """foo ~~~bar~ baz\n""" + var html = """

    foo bar baz

    \n""" + assert md_to_html(md) == html + end + + fun test_strike_bad4 is test do + var md = """foo ~~~~bar~ baz\n""" + var html = """

    foo bar baz

    \n""" + assert md_to_html(md) == html + end + + fun test_strike_bad5 is test do + var md = """foo ~~~~~bar~ baz\n""" + var html = """

    foo bar baz

    \n""" + assert md_to_html(md) == html + end + + fun test_strike_bad6 is test do + var md = """foo bar~ baz\n""" + var html = """

    foo bar~ baz

    \n""" + assert md_to_html(md) == html + end + + fun test_strike_bad7 is test do + var md = """foo ~bar~~~~ baz\n""" + var html = """

    foo bar~~~ baz

    \n""" + assert md_to_html(md) == html + end + + fun test_super1 is test do + var md = """foo ^bar^ baz\n""" + var html = """

    foo bar baz

    \n""" + assert md_to_html(md) == html + end + + fun test_super2 is test do + var md = """foo ^^bar^^ baz\n""" + var html = """

    foo bar baz

    \n""" + assert md_to_html(md) == html + end + + fun test_super3 is test do + var md = """foo ^^^bar^^^ baz\n""" + var html = """

    foo bar baz

    \n""" + assert md_to_html(md) == html + end + + fun test_super4 is test do + var md = """foo ^^^^bar^^^^ baz\n""" + var html = """

    foo bar baz

    \n""" + assert md_to_html(md) == html + end + + fun test_super5 is test do + var md = """foo ^^^^^bar^^^^^ baz\n""" + var html = """

    foo bar baz

    \n""" + assert md_to_html(md) == html + end + + fun test_super6 is test do + var md = """foo ^^^^^^bar^^^^^^ baz\n""" + var html = """

    foo bar baz

    \n""" + assert md_to_html(md) == html + end + + fun test_super_bad1 is test do + var md = """foo ^bar baz\n""" + var html = """

    foo ^bar baz

    \n""" + assert md_to_html(md) == html + end + + fun test_super_bad is test do + var md = """foo ^^bar^ baz\n""" + var html = """

    foo bar baz

    \n""" + assert md_to_html(md) == html + end + + fun test_super_bad3 is test do + var md = """foo ^^^bar^ baz\n""" + var html = """

    foo bar baz

    \n""" + assert md_to_html(md) == html + end + + fun test_super_bad4 is test do + var md = """foo ^^^^bar^ baz\n""" + var html = """

    foo bar baz

    \n""" + assert md_to_html(md) == html + end + + fun test_super_bad5 is test do + var md = """foo ^^^^^bar^ baz\n""" + var html = """

    foo bar baz

    \n""" + assert md_to_html(md) == html + end + + fun test_super_bad6 is test do + var md = """foo bar^ baz\n""" + var html = """

    foo bar^ baz

    \n""" + assert md_to_html(md) == html + end + + fun test_super_bad7 is test do + var md = """foo ^bar^^^^ baz\n""" + var html = """

    foo bar^^^ baz

    \n""" + assert md_to_html(md) == html + end +end + +class TestGithubMd + super TestMarkdownMd + test + + fun test_strike_md is test do + var md = """~~foo~~\n""" + assert md_to_md(md) == md + end + + fun test_super_md is test do + var md = """^^foo^^\n""" + assert md_to_md(md) == md + end +end + +class TestGithubMan + super TestMarkdownMan + test + + fun test_strike_man is test do + var md = """~~foo~~\n""" + var man = """\n[STRIKEOUT:foo]\n""" + assert md_to_man(md) == man + end + + fun test_super_man is test do + var md = """^foo^\n""" + var man = """\nfoo\n""" + assert md_to_man(md) == man + end +end + +class TestGithubLatex + super TestMarkdownLatex + test + + fun test_strike_latex is test do + var md = """ +A ~~super~~ text. +""" + var tex = """ +A \\sout{super} text. +""" + assert md_to_tex(md) == tex + end + + fun test_super_latex is test do + var md = """ +A ^super^ text. +""" + var tex = """ +A \\textsuperscript{super} text. +""" + assert md_to_tex(md) == tex + end +end diff --git a/lib/markdown2/tests/test_markdown_headings_id.nit b/lib/markdown2/tests/test_markdown_headings_id.nit new file mode 100644 index 0000000..28f91a3 --- /dev/null +++ b/lib/markdown2/tests/test_markdown_headings_id.nit @@ -0,0 +1,61 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Test for markdown headings id generation +module test_markdown_headings_id is test + +import test_markdown + +class TestMarkdownHeadingsId + super TestMarkdownHtml + test + + redef var html_renderer = new HtmlRenderer(true) + + fun test_multiple_ids is test do + var md = """# foo\n## foo\n### foo\n#### foo\n##### foo\n###### foo\n""" + var html = """

    foo

    \n

    foo

    \n

    foo

    \n

    foo

    \n
    foo
    \n
    foo
    \n""" + assert md_to_html(md) == html + end + + fun test_escape_ids is test do + var md = """# foo *bar* \\*baz\\*\n""" + var html = """

    foo bar *baz*

    \n""" + assert md_to_html(md) == html + end + + fun test_escape_ids2 is test do + var md = """# foo#\n""" + var html = """

    foo#

    \n""" + assert md_to_html(md) == html + end + + fun test_avoid_spaces is test do + var md = """# foo \n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test_remove_atx_trailing is test do + var md = """## foo ##\n ### bar ###\n""" + var html = """

    foo

    \n

    bar

    \n""" + assert md_to_html(md) == html + end + + fun test_avoid_escaped_chars is test do + var md = """### foo \\###\n## foo #\\##\n# foo \\#\n""" + var html = """

    foo ###

    \n

    foo ###

    \n

    foo #

    \n""" + assert md_to_html(md) == html + end +end diff --git a/lib/markdown2/tests/test_markdown_inlines.nit b/lib/markdown2/tests/test_markdown_inlines.nit new file mode 100644 index 0000000..6a21084 --- /dev/null +++ b/lib/markdown2/tests/test_markdown_inlines.nit @@ -0,0 +1,335 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either htmlress or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Tests for markdown inline constructs +module test_markdown_inlines is test + +import test_markdown + +class TestMarkdownInlines + super TestMarkdownHtml + test + + fun test_inlines_emph1 is test do + var md = """ +*single asterisks* + +_single underscores_ + +**double asterisks** + +__double underscores__ +""" + var html = """

    single asterisks

    +

    single underscores

    +

    double asterisks

    +

    double underscores

    +""" + assert md_to_html(md) == html + end + + fun test_inlines_emph2 is test do + var md = "un*frigging*believable" + var html = "

    unfriggingbelievable

    \n" + assert md_to_html(md) == html + end + + fun test_inlines_emph3 is test do + var md = "Con _cat_ this" + var html = "

    Con cat this

    \n" + assert md_to_html(md) == html + end + + fun test_inlines_emph_ext is test do + var md = "Con_cat_this" + var html = "

    Con_cat_this

    \n" + assert md_to_html(md) == html + end + + fun test_inlines_xml1 is test do + var md = """ +This is a regular paragraph. + + + + + +
    Foo
    + +This is another regular paragraph. +""" + var html = """ +

    This is a regular paragraph.

    + + + + +
    Foo
    +

    This is another regular paragraph.

    +""" + assert md_to_html(md) == html + end + + fun test_inlines_xml2 is test do + var md = """ +This is an image baz in a regular paragraph. +""" + var html = """ +

    This is an image baz in a regular paragraph.

    +""" + assert md_to_html(md) == html + end + + fun test_inlines_xml3 is test do + var md = """ +
    +""" + var html = """ +
    +""" + assert md_to_html(md) == html + end + + fun test_inlines_xml4 is test do + var md = """ +

    This is an example of a block element that should be escaped.

    +

    Idem for the second paragraph.

    +""" + assert md_to_html(md) == md + end + + fun test_inlines_xml5 is test do + var md = """ +# Some more XML tests + +

    This is an example of a block element that should be escaped.

    +

    Idem for the second paragraph.

    + +With a *md paragraph*! +""" + var html = """ +

    Some more XML tests

    +

    This is an example of a block element that should be escaped.

    +

    Idem for the second paragraph.

    +

    With a md paragraph!

    +""" + assert md_to_html(md) == html + end + + fun test_escape_bad_html is test do + var md = "-1 if < , +1 if > and 0 otherwise" + var html = "

    -1 if < , +1 if > and 0 otherwise

    \n" + assert md_to_html(md) == html + end + + fun test_inlines_span_code1 is test do + var md = "Use the `printf()` function." + var html = "

    Use the printf() function.

    \n" + assert md_to_html(md) == html + end + + fun test_inlines_span_code2 is test do + var md = "``There is a literal backtick (`) here.``" + var html = "

    There is a literal backtick (`) here.

    \n" + assert md_to_html(md) == html + end + + fun test_inlines_span_code3 is test do + var md = """ +A single backtick in a code span: `` ` `` + +A backtick-delimited string in a code span: `` `foo` `` +""" + var html = """ +

    A single backtick in a code span: `

    +

    A backtick-delimited string in a code span: `foo`

    +""" + assert md_to_html(md) == html + end + + fun test_inlines_span_code4 is test do + var md = "Please don't use any `` tags." + var html = "

    Please don't use any <blink> tags.

    \n" + assert md_to_html(md) == html + end + + fun test_inlines_span_code5 is test do + var md = "`—` is the decimal-encoded equivalent of `—`." + var html = "

    &#8212; is the decimal-encoded equivalent of &mdash;.

    \n" + assert md_to_html(md) == html + end + + fun test_inlines_escape1 is test do + var md = "\\*this text is surrounded by literal asterisks\\*" + var html = "

    *this text is surrounded by literal asterisks*

    \n" + assert md_to_html(md) == html + end + + fun test_inlines_escape2 is test do + var md = "1986\\. What a great season." + var html = "

    1986. What a great season.

    \n" + assert md_to_html(md) == html + end + + fun test_inlines_escape3 is test do + var md = "Ben & Lux" + var html = "

    Ben & Lux

    \n" + assert md_to_html(md) == html + end + + fun test_inlines_link1 is test do + var md = """ +This is [an example](http://example.com/ "Title") inline link. + +[This link](http://example.net/) has no title attribute. +""" + var html = """

    This is an example inline link.

    +

    This link has no title attribute.

    +""" + assert md_to_html(md) == html + end + + fun test_inlines_link2 is test do + var md = "See my [About](/about/) page for details." + var html = "

    See my About page for details.

    \n" + assert md_to_html(md) == html + end + + fun test_inlines_link3 is test do + var md = """ +This is [an example][id] reference-style link. + +Some lorem ipsum + +[id]: http://example.com/ "Optional Title Here" + +Some other lipsum +""" + var html = """ +

    This is an example reference-style link.

    +

    Some lorem ipsum

    +

    Some other lipsum

    +""" + assert md_to_html(md) == html + end + + fun test_inlines_link4 is test do + var md = """ +This is multiple examples: [foo][1], [bar][2], [baz][3]. + +[1]: http://example.com/ "Optional Title Here" +[2]: http://example.com/ 'Optional Title Here' +[3]: http://example.com/ (Optional Title Here) +""" + var html = """ +

    This is multiple examples: foo, bar, baz.

    +""" + assert md_to_html(md) == html + end + + fun test_inlines_link5 is test do + var md = """ +This is multiple examples: [foo][a], [bar][A], [a]. + +[a]: http://example.com/ "Optional Title Here" +""" + var html = """

    This is multiple examples: foo, bar, a.

    +""" + assert md_to_html(md) == html + end + + fun test_inlines_link6 is test do + var md = """ +I get 10 times more traffic from [Google][] than from [Yahoo][] or [MSN][]. + +[Google]: http://google.com/ "Google" +[Yahoo]: http://search.yahoo.com/ "Yahoo Search" +[MSN]: http://search.msn.com/ "MSN Search" +""" + var html = """

    I get 10 times more traffic from Google than from Yahoo or MSN.

    +""" + assert md_to_html(md) == html + end + + fun test_inlines_link7 is test do + var md = """ +Visit [Daring Fireball][] for more information. + +[Daring Fireball]: http://daringfireball.net/ +""" + var html = """

    Visit Daring Fireball for more information.

    +""" + assert md_to_html(md) == html + end + + fun test_inlines_link8 is test do + var md = """ +This one has a [line +break]. + +This one has a [line +break] with a line-ending space. + +[line break]: /foo +""" + var html = """ +

    This one has a line +break.

    +

    This one has a line +break with a line-ending space.

    +""" + assert md_to_html(md) == html + end + + fun test_inlines_link9 is test do + var md = """ +Foo [bar][]. + +Foo [bar](/url/ "Title with \\"quotes\\" inside"). + + +[bar]: /url/ "Title with \\"quotes\\" inside" +""" + var html = """ +

    Foo bar.

    +

    Foo bar.

    +""" + assert md_to_html(md) == html + end + + fun test_inlines_img1 is test do + var md = """ +![Alt text](/path/to/img.jpg) + +![Alt text](/path/to/img.jpg "Optional title") +""" + var html = """ +

    Alt text

    +

    Alt text

    +""" + assert md_to_html(md) == html + end + + fun test_inlines_img2 is test do + var md = """ +![Alt text][id] + +[id]: url/to/image "Optional title attribute" +""" + var html = """ +

    Alt text

    +""" + assert md_to_html(md) == html + end +end diff --git a/lib/markdown2/tests/test_markdown_issues.nit b/lib/markdown2/tests/test_markdown_issues.nit new file mode 100644 index 0000000..c8deb1b --- /dev/null +++ b/lib/markdown2/tests/test_markdown_issues.nit @@ -0,0 +1,152 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Tests related to markdown issues from the Git repo +# +# Fixing: +# +# * 1525: lib/markdown: issue with nested fences +# * 2507: markdown: some lines are lost in verbatim blocks inside a list +# +# See . +module test_markdown_issues is test + +import test_markdown + +class TestMarkdownIssues + super TestMarkdownHtml + test + + # See . + fun test_issue_1525_1 is test do + var md = """ +A fence within a fence +~~~~~~ +some code: +~~~ +some other code +~~~ +~~~~~~ +""" + var html = """ +

    A fence within a fence

    +
    some code:
    +~~~
    +some other code
    +~~~
    +
    +""" + assert md_to_html(md) == html + end + + # See . + fun test_issue_1525_2 is test do + var md = """ +A fence within a fence +~~~ +some code: +``` +some other code +``` +~~~ +""" + var html = """ +

    A fence within a fence

    +
    some code:
    +```
    +some other code
    +```
    +
    +""" + assert md_to_html(md) == html + end + + # See . + fun test_issue_1525_3 is test do + var md = """ +A fence within a fence +``` +some code: +~~~ +some other code +~~~ +``` +""" + var html = """ +

    A fence within a fence

    +
    some code:
    +~~~
    +some other code
    +~~~
    +
    +""" + assert md_to_html(md) == html + end + + # See . + fun test_issue_2507_1 is test do + var md = """ +* 4 spaces, `asdf` and `tab.` are lost + ~~~ + a + as + asd + asdf + tab. + asdfg + ~~~ +""" + var html = """ +
      +
    • 4 spaces, asdf and tab. are lost +
      a
      +as
      +asd
      +asdf
      +	tab.
      +asdfg
      +
      +
    • +
    +""" + assert md_to_html(md) == html + end + + # See . + fun test_issue_2507_2 is test do + var md = """ +* 2 spaces, `as` is lost + + ~~~ + a + as + asd + asdf + ~~~ +""" + var html = """ +
      +
    • +

      2 spaces, as is lost

      +
      a
      +as
      +asd
      +asdf
      +
      +
    • +
    +""" + assert md_to_html(md) == html + end +end diff --git a/lib/markdown2/tests/test_markdown_latex.nit b/lib/markdown2/tests/test_markdown_latex.nit new file mode 100644 index 0000000..ec85616 --- /dev/null +++ b/lib/markdown2/tests/test_markdown_latex.nit @@ -0,0 +1,542 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Tests for markdown rendering to LaTeX +module test_markdown_latex is test + +import test_markdown +import markdown_latex_rendering + +# Abstract test class that defines the test methods for LaTeX rendering +abstract class TestMarkdownLatex + super TestMarkdown + + # LaTeX renderer used in tests + var tex_renderer = new LatexRenderer + + # Render the `md` string as LaTeX format + fun md_to_tex(md: String): String do + var node = parse_md(md) + return tex_renderer.render(node) + end +end + +class TestLatexRendering + super TestMarkdownLatex + test + + fun after_test is after do + tex_renderer.wrap_document = false + tex_renderer.use_listings = false + end + + fun test_document_wrapper is test do + var md = """ +This example needs a document wrapper. +""" + + var tex = """ +\\documentclass[letter,10pt]{article} + +\\usepackage[utf8]{inputenc} +\\usepackage{hyperref} +\\usepackage{graphicx} +\\usepackage{ulem} + +\\begin{document} + +This example needs a document wrapper. + +\\end{document} +""" + tex_renderer.wrap_document = true + assert md_to_tex(md) == tex + end + + fun test_atx_headings is test do + var md = """ +# Title 1 +## Title 2 +### Title 3 +#### Title 4 +##### Title 5 +###### Title 6 +""" + var tex = """ +\\section{Title 1} + +\\subsection{Title 2} + +\\subsubsection{Title 3} + +\\paragraph{Title 4} + +\\subparagraph{Title 5} + +\\textbf{Title 6} +""" + assert md_to_tex(md) == tex + end + + fun test_blockquotes is test do + var md = """ +> this is a +> multiline quote +""" + var tex = """ +\\begin{quote} + this is a + multiline quote +\\end{quote} +""" + assert md_to_tex(md) == tex + end + + fun test_thematic_breaks is test do + var md = """ +* * * +""" + var tex = """ +\\begin{center}\\rule{3in}{0.4pt}\\end{center} +""" + assert md_to_tex(md) == tex + end + + fun test_paragraphs is test do + var md = """ +a paragraph +on two lines + +another paragraph +""" + var tex = """ +a paragraph +on two lines + +another paragraph +""" + assert md_to_tex(md) == tex + end + + fun test_html_block is test do + var md = """ +

    + foo +

    + """ + var tex = """ +\\begin{verbatim} +

    + foo +

    +\\end{verbatim} +""" + assert md_to_tex(md) == tex + end + + fun test_indented_code is test do + var md = """ + first line + second line +""" + var tex = """ +\\begin{verbatim} +first line +second line +\\end{verbatim} +""" + assert md_to_tex(md) == tex + end + + fun test_indented_code_with_listings is test do + var md = """ + first line + second line +""" + var tex = """ +\\begin{lstlisting} +first line +second line +\\end{lstlisting} +""" + tex_renderer.use_listings = true + assert md_to_tex(md) == tex + end + + fun test_fenced_code is test do + var md = """ +~~~ +first line +second line +~~~ +""" + var tex = """ +\\begin{verbatim} +first line +second line +\\end{verbatim} +""" + assert md_to_tex(md) == tex + end + + fun test_fenced_code_with_listings is test do + var md = """ +~~~ +first line +second line +~~~ +""" + var tex = """ +\\begin{lstlisting} +first line +second line +\\end{lstlisting} +""" + tex_renderer.use_listings = true + assert md_to_tex(md) == tex + end + + fun test_fenced_code_with_listings_and_language is test do + var md = """ +~~~c +first line +second line +~~~ +""" + var tex = """ +\\begin{lstlisting}[language=c] +first line +second line +\\end{lstlisting} +""" + tex_renderer.use_listings = true + assert md_to_tex(md) == tex + end + + fun test_list_ordered is test do + var md = """ +1) item 1 +2) item 2 +""" + var tex = """ +\\begin{enumerate} + \\item + item 1 + \\item + item 2 +\\end{enumerate} +""" + assert md_to_tex(md) == tex + end + + fun test_list_ordered_with_starting_number is test do + var md = """ +4) item 1 +5) item 2 +""" + var tex = """ +\\begin{enumerate} + \\setcounter{enumi}{4} + \\item + item 1 + \\item + item 2 +\\end{enumerate} +""" + assert md_to_tex(md) == tex + end + + fun test_list_unordered is test do + var md = """ +* item 1 +* item 2 +""" + var tex = """ +\\begin{itemize} + \\item + item 1 + \\item + item 2 +\\end{itemize} +""" + assert md_to_tex(md) == tex + end + + fun test_list_nested is test do + var md = """ +* item 1 +* item 2 + 1) item 3 + 2) item 4 +""" + var tex = """ +\\begin{itemize} + \\item + item 1 + \\item + item 2 + \\begin{enumerate} + \\item + item 3 + \\item + item 4 + \\end{enumerate} +\\end{itemize} +""" + assert md_to_tex(md) == tex + end + + fun test_ordered_list_nested is test do + var md = """ +4) item 1 +5) item 2 + + 4) item 3 + 5) item 4 + + 4) item 3 + 5) item 4 + + 4) item 3 + 5) item 4 +""" + var tex = """ +\\begin{enumerate} + \\setcounter{enumi}{4} + \\item + item 1 + \\item + item 2 + \\begin{enumerate} + \\setcounter{enumii}{4} + \\item + item 3 + \\item + item 4 + \\begin{enumerate} + \\setcounter{enumiii}{4} + \\item + item 3 + \\item + item 4 + \\begin{enumerate} + \\setcounter{enumiv}{4} + \\item + item 3 + \\item + item 4 + \\end{enumerate} + \\end{enumerate} + \\end{enumerate} +\\end{enumerate} +""" + assert md_to_tex(md) == tex + end + + fun test_list_and_blockquote is test do + var md = """ +* item 1 +* item 2 + > quote 1 + > quote 2 +""" + var tex = """ +\\begin{itemize} + \\item + item 1 + \\item + item 2 + \\begin{quote} + quote 1 + quote 2 + \\end{quote} +\\end{itemize} +""" + assert md_to_tex(md) == tex + end + + fun test_blockquote_and_list is test do + var md = """ +> line 1 +> line 2 +> * item 1 +> * item 2 +""" + var tex = """ +\\begin{quote} + line 1 + line 2 + \\begin{itemize} + \\item + item 1 + \\item + item 2 + \\end{itemize} +\\end{quote} +""" + assert md_to_tex(md) == tex + end + + fun test_code is test do + var md = """ +An `inline code`. +""" + var tex = """ +An \\texttt{inline code}. +""" + assert md_to_tex(md) == tex + end + + fun test_emphasis is test do + var md = """ +An *emphasis* and a **strong emphasis**. +""" + var tex = """ +An \\textit{emphasis} and a \\textbf{strong emphasis}. +""" + assert md_to_tex(md) == tex + end + + fun test_autolink is test do + var md = """ + +""" + var tex = """ +\\url{http://test} +""" + assert md_to_tex(md) == tex + end + + fun test_link is test do + var md = """ +A [link](url/). +""" + var tex = """ +A \\href{url/}{link}. +""" + assert md_to_tex(md) == tex + end + + fun test_link_with_title is test do + var md = """ +A [link](url/ "with a title"). +""" + var tex = """ +A \\href{url/}{link (with a title)}. +""" + assert md_to_tex(md) == tex + end + + fun test_image is test do + var md = """ +![image](url/). +""" + var tex = """ +\\includegraphics{url/}. +""" + assert md_to_tex(md) == tex + end + + fun test_softbreak is test do + var md = """ +A soft +break. +""" + var tex = """ +A soft +break. +""" + assert md_to_tex(md) == tex + end + + fun test_hardbreak is test do + var md = """ +A hard\\ +break. +""" + var tex = """ +A hard +break. +""" + assert md_to_tex(md) == tex + end + + fun test_escaped is test do + var md = """ +An escaped \\*. +""" + var tex = """ +An escaped *. +""" + assert md_to_tex(md) == tex + end + + fun test_forbidden_chars is test do + var md = """ +%${_><#&}\\ +""" + var tex = """ +\\%\\$\\{\\_\\textgreater\\textless\\#\\&\\}\\textbackslash +""" + assert md_to_tex(md) == tex + end + + fun test_full_document is test do + var md = """ +# Title + +A paragraph. + +## Another title + +A list: + +1. item 1 +2. item 2 + +A code example: + + line 1 + line 2 + +Another paragraph. +""" + var tex = """ +\\section{Title} + +A paragraph. + +\\subsection{Another title} + +A list: + +\\begin{enumerate} + \\item + item 1 + \\item + item 2 +\\end{enumerate} + +A code example: + +\\begin{verbatim} +line 1 +line 2 +\\end{verbatim} + +Another paragraph. +""" + assert md_to_tex(md) == tex + end +end diff --git a/lib/markdown2/tests/test_markdown_location.nit b/lib/markdown2/tests/test_markdown_location.nit new file mode 100644 index 0000000..4aaa218 --- /dev/null +++ b/lib/markdown2/tests/test_markdown_location.nit @@ -0,0 +1,913 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Tests for markdown nodes location +module test_markdown_location is test + +import test_markdown + +abstract class TestMarkdownLocation + super TestMarkdown + + redef var md_parser do + var parser = super + parser.github_mode = true + parser.wikilinks_mode = true + return parser + end + + fun md_to_loc(md: String): String do + var node = parse_md(md) + var v = new TestMarkdownLocationVisitor + v.enter_visit(node) + return v.buffer.to_s + end +end + +class TestMarkdownLocationVisitor + super MdVisitor + + var buffer = new Buffer + var indent = 0 + + fun print_loc(node: MdNode) do + buffer.append "{" " * indent}{node.class_name}: {node.location}\n" + indent += 1 + node.visit_all(self) + indent -= 1 + end + + redef fun visit(node) do print_loc(node) +end + +class TestLocationOutput + super TestMarkdownLocation + test + + fun test_atx_headings1 is test do + var md = """ +# title 1 +## title 2 +### title 3 +#### title 4 +##### title 5 +###### title 6 +""" + var loc = """ +MdDocument: 1,1--6,14 + MdHeading: 1,1--1,9 + MdText: 1,3--1,9 + MdHeading: 2,1--2,10 + MdText: 2,4--2,10 + MdHeading: 3,1--3,11 + MdText: 3,5--3,11 + MdHeading: 4,1--4,12 + MdText: 4,6--4,12 + MdHeading: 5,1--5,13 + MdText: 5,7--5,13 + MdHeading: 6,1--6,14 + MdText: 6,8--6,14 +""" + assert md_to_loc(md) == loc + end + + fun test_atx_headings_with_trailings is test do + var md = """ +# title 1 # +## title 2 ## +### title 3 ### +#### title 4 #### +##### title 5 ##### +###### title 6 ###### +""" + var loc = """ +MdDocument: 1,1--6,21 + MdHeading: 1,1--1,11 + MdText: 1,3--1,9 + MdHeading: 2,1--2,13 + MdText: 2,4--2,10 + MdHeading: 3,1--3,15 + MdText: 3,5--3,11 + MdHeading: 4,1--4,17 + MdText: 4,6--4,12 + MdHeading: 5,1--5,19 + MdText: 5,7--5,13 + MdHeading: 6,1--6,21 + MdText: 6,8--6,14 +""" + assert md_to_loc(md) == loc + end + + fun test_settext_headings is test do + var md = """ +title 1 +======= + +title 2 +------- +""" + var loc = """ +MdDocument: 1,1--5,7 + MdHeading: 1,1--2,7 + MdText: 1,1--1,7 + MdHeading: 4,1--5,7 + MdText: 4,1--4,7 +""" + assert md_to_loc(md) == loc + end + + fun test_indented_code_spaces is test do + var md = """ + some code + + multi lines +""" + var loc = """ +MdDocument: 1,1--3,15 + MdIndentedCodeBlock: 1,1--3,15 +""" + assert md_to_loc(md) == loc + end + + fun test_indented_code_tabs is test do + var md = """ + some code + + multi lines +""" + var loc = """ +MdDocument: 1,1--3,15 + MdIndentedCodeBlock: 1,1--3,15 +""" + assert md_to_loc(md) == loc + end + + fun test_fenced_code is test do + var md = """ +~~~ +some code + +multi lines +~~~ +""" + var loc = """ +MdDocument: 1,1--5,3 + MdFencedCodeBlock: 1,1--5,3 +""" + assert md_to_loc(md) == loc + end + + fun test_thematic_breaks is test do + var md = """ +*** + +* * * + +* * * +""" + var loc = """ +MdDocument: 1,1--5,5 + MdThematicBreak: 1,1--1,3 + MdThematicBreak: 3,1--3,5 + MdThematicBreak: 5,1--5,5 +""" + assert md_to_loc(md) == loc + end + + fun test_html_blocks1 is test do + var md = """ +

    bar

    + +
    + bar +

    +""" + var loc = """ +MdDocument: 1,1--5,12 + MdHtmlBlock: 1,1--1,28 + MdHtmlBlock: 3,1--5,12 +""" + assert md_to_loc(md) == loc + end + + fun test_paragraph1 is test do + var md = """ +foo bar baz + +line 1 +line 2 + +other par +with multiple lines +""" + var loc = """ +MdDocument: 1,1--7,19 + MdParagraph: 1,1--1,11 + MdText: 1,1--1,11 + MdParagraph: 3,1--4,6 + MdText: 3,1--3,6 + MdSoftLineBreak: 3,7--3,7 + MdText: 4,1--4,6 + MdParagraph: 6,1--7,19 + MdText: 6,1--6,9 + MdSoftLineBreak: 6,10--6,10 + MdText: 7,1--7,19 +""" + assert md_to_loc(md) == loc + end + + fun test_blockquotes is test do + var md = """ +> foo +> bar +""" + var loc = """ +MdDocument: 1,1--2,5 + MdBlockQuote: 1,1--2,5 + MdParagraph: 1,3--2,5 + MdText: 1,3--1,5 + MdSoftLineBreak: 1,6--1,6 + MdText: 2,3--2,5 +""" + assert md_to_loc(md) == loc + end + + fun test_blockquotes_nested is test do + var md = """ +> foo +> > foo +> > bar +""" + var loc = """ +MdDocument: 1,1--3,7 + MdBlockQuote: 1,1--3,7 + MdParagraph: 1,3--1,5 + MdText: 1,3--1,5 + MdBlockQuote: 2,3--3,7 + MdParagraph: 2,5--3,7 + MdText: 2,5--2,7 + MdSoftLineBreak: 2,8--2,8 + MdText: 3,5--3,7 +""" + assert md_to_loc(md) == loc + end + + fun test_blockquotes_headings is test do + var md = """ +> # Title 1 +> ## Title 2 ## +""" + var loc = """ +MdDocument: 1,1--2,15 + MdBlockQuote: 1,1--2,15 + MdHeading: 1,3--1,11 + MdText: 1,5--1,11 + MdHeading: 2,3--2,15 + MdText: 2,6--2,12 +""" + assert md_to_loc(md) == loc + end + + fun test_blockquotes_thematic_breaks is test do + var md = """ +> *** +> * * * +""" + var loc = """ +MdDocument: 1,1--2,7 + MdBlockQuote: 1,1--2,7 + MdThematicBreak: 1,3--1,5 + MdThematicBreak: 2,3--2,7 +""" + assert md_to_loc(md) == loc + end + + fun test_blockquotes_indented_code is test do + var md = """ +> line 1 +> line 2 +""" + var loc = """ +MdDocument: 1,1--2,12 + MdBlockQuote: 1,1--2,12 + MdIndentedCodeBlock: 1,3--2,12 +""" + assert md_to_loc(md) == loc + end + + fun test_blockquotes_fenced_code is test do + var md = """ +> ~~~ +> line 1 +> line 2 +> ~~~ +""" + var loc = """ +MdDocument: 1,1--4,5 + MdBlockQuote: 1,1--4,5 + MdFencedCodeBlock: 1,3--4,5 +""" + assert md_to_loc(md) == loc + end + + fun test_blockquotes_list is test do + var md = """ +> * line 1 +> * line 2 +""" + var loc = """ +MdDocument: 1,1--2,10 + MdBlockQuote: 1,1--2,10 + MdUnorderedList: 1,3--2,10 + MdListItem: 1,3--1,10 + MdParagraph: 1,5--1,10 + MdText: 1,5--1,10 + MdListItem: 2,3--2,10 + MdParagraph: 2,5--2,10 + MdText: 2,5--2,10 +""" + assert md_to_loc(md) == loc + end + + fun test_unordered_lists is test do + var md = """ +* line 1 +* line 2 +""" + var loc = """ +MdDocument: 1,1--2,8 + MdUnorderedList: 1,1--2,8 + MdListItem: 1,1--1,8 + MdParagraph: 1,3--1,8 + MdText: 1,3--1,8 + MdListItem: 2,1--2,8 + MdParagraph: 2,3--2,8 + MdText: 2,3--2,8 +""" + assert md_to_loc(md) == loc + end + + fun test_ordered_lists is test do + var md = """ +1) line 1 +2) line 2 +""" + var loc = """ +MdDocument: 1,1--2,9 + MdOrderedList: 1,1--2,9 + MdListItem: 1,1--1,9 + MdParagraph: 1,4--1,9 + MdText: 1,4--1,9 + MdListItem: 2,1--2,9 + MdParagraph: 2,4--2,9 + MdText: 2,4--2,9 +""" + assert md_to_loc(md) == loc + end + + fun test_list_headings is test do + var md = """ +* # Title 1 +* ## Title 2 ## +""" + var loc = """ +MdDocument: 1,1--2,15 + MdUnorderedList: 1,1--2,15 + MdListItem: 1,1--1,11 + MdHeading: 1,3--1,11 + MdText: 1,5--1,11 + MdListItem: 2,1--2,15 + MdHeading: 2,3--2,15 + MdText: 2,6--2,12 +""" + assert md_to_loc(md) == loc + end + + fun test_list_thematic_breaks is test do + var md = """ +- *** +- * * * +""" + var loc = """ +MdDocument: 1,1--2,7 + MdUnorderedList: 1,1--2,7 + MdListItem: 1,1--1,5 + MdThematicBreak: 1,3--1,5 + MdListItem: 2,1--2,7 + MdThematicBreak: 2,3--2,7 +""" + assert md_to_loc(md) == loc + end + + fun test_list_indented_codes is test do + var md = """ +- line 1 +- line 2 +""" + var loc = """ +MdDocument: 1,1--2,12 + MdUnorderedList: 1,1--2,12 + MdListItem: 1,1--1,12 + MdIndentedCodeBlock: 1,3--1,12 + MdListItem: 2,1--2,12 + MdIndentedCodeBlock: 2,3--2,12 +""" + assert md_to_loc(md) == loc + end + + fun test_list_fenced_codes is test do + var md = """ +- ~~~ + line 1 + line 2 + ~~~ +""" + var loc = """ +MdDocument: 1,1--4,5 + MdUnorderedList: 1,1--4,5 + MdListItem: 1,1--4,5 + MdFencedCodeBlock: 1,3--4,5 +""" + assert md_to_loc(md) == loc + end + + fun test_list_blockquotes is test do + var md = """ +- > line 1 + > line 2 +""" + var loc = """ +MdDocument: 1,1--2,10 + MdUnorderedList: 1,1--2,10 + MdListItem: 1,1--2,10 + MdBlockQuote: 1,3--2,10 + MdParagraph: 1,5--2,10 + MdText: 1,5--1,10 + MdSoftLineBreak: 1,11--1,11 + MdText: 2,5--2,10 +""" + assert md_to_loc(md) == loc + end + + fun test_list_pars is test do + var md = """ +* line 1 + line 2 + +* line 3 +""" + var loc = """ +MdDocument: 1,1--4,8 + MdUnorderedList: 1,1--4,8 + MdListItem: 1,1--2,8 + MdParagraph: 1,3--2,8 + MdText: 1,3--1,8 + MdSoftLineBreak: 1,9--1,9 + MdText: 2,3--2,8 + MdListItem: 4,1--4,8 + MdParagraph: 4,3--4,8 + MdText: 4,3--4,8 +""" + assert md_to_loc(md) == loc + end + + fun test_list_nested is test do + var md = """ +* foo + * foo + * bar +""" + var loc = """ +MdDocument: 1,1--3,7 + MdUnorderedList: 1,1--3,7 + MdListItem: 1,1--3,7 + MdParagraph: 1,3--1,5 + MdText: 1,3--1,5 + MdUnorderedList: 2,3--3,7 + MdListItem: 2,3--2,7 + MdParagraph: 2,5--2,7 + MdText: 2,5--2,7 + MdListItem: 3,3--3,7 + MdParagraph: 3,5--3,7 + MdText: 3,5--3,7 +""" + assert md_to_loc(md) == loc + end + + fun test_emphasis is test do + var md = """ +An *emphasis* and a **strong emphasis**. +""" + var loc = """ +MdDocument: 1,1--1,40 + MdParagraph: 1,1--1,40 + MdText: 1,1--1,3 + MdEmphasis: 1,4--1,13 + MdText: 1,5--1,12 + MdText: 1,14--1,20 + MdStrongEmphasis: 1,21--1,39 + MdText: 1,23--1,37 + MdText: 1,40--1,40 +""" + assert md_to_loc(md) == loc + end + + fun test_emphasis_nested is test do + var md = """ +Another ***emphasis***. +""" + var loc = """ +MdDocument: 1,1--1,23 + MdParagraph: 1,1--1,23 + MdText: 1,1--1,8 + MdEmphasis: 1,9--1,22 + MdStrongEmphasis: 1,10--1,21 + MdText: 1,12--1,19 + MdText: 1,23--1,23 +""" + assert md_to_loc(md) == loc + end + + fun test_emphasis_nested2 is test do + var md = """ +Another ****emphasis****. +""" + var loc = """ +MdDocument: 1,1--1,25 + MdParagraph: 1,1--1,25 + MdText: 1,1--1,8 + MdStrongEmphasis: 1,9--1,24 + MdStrongEmphasis: 1,11--1,22 + MdText: 1,13--1,20 + MdText: 1,25--1,25 +""" + assert md_to_loc(md) == loc + end + + fun test_emphasis_nested3 is test do + var md = """ +Another *****emphasis*****. +""" + var loc = """ +MdDocument: 1,1--1,27 + MdParagraph: 1,1--1,27 + MdText: 1,1--1,8 + MdEmphasis: 1,9--1,26 + MdStrongEmphasis: 1,10--1,25 + MdStrongEmphasis: 1,12--1,23 + MdText: 1,14--1,21 + MdText: 1,27--1,27 +""" + assert md_to_loc(md) == loc + end + + fun test_emphasis_bad is test do + var md = """ +Another ___ emphasis ___. +""" + var loc = """ +MdDocument: 1,1--1,25 + MdParagraph: 1,1--1,25 + MdText: 1,1--1,25 +""" + assert md_to_loc(md) == loc + end + + fun test_emphasis_bad2 is test do + var md = """ +Another **emphasis. +""" + var loc = """ +MdDocument: 1,1--1,19 + MdParagraph: 1,1--1,19 + MdText: 1,1--1,19 +""" + assert md_to_loc(md) == loc + end + + fun test_inline_code is test do + var md = """ +A `code` and another ``one``. +""" + var loc = """ +MdDocument: 1,1--1,29 + MdParagraph: 1,1--1,29 + MdText: 1,1--1,2 + MdCode: 1,3--1,8 + MdText: 1,9--1,21 + MdCode: 1,22--1,28 + MdText: 1,29--1,29 +""" + assert md_to_loc(md) == loc + end + + fun test_inline_code_bad is test do + var md = """ +A `code and another ``one``. +""" + var loc = """ +MdDocument: 1,1--1,28 + MdParagraph: 1,1--1,28 + MdText: 1,1--1,20 + MdCode: 1,21--1,27 + MdText: 1,28--1,28 +""" + assert md_to_loc(md) == loc + end + + fun test_inline_autolink is test do + var md = """ +An . +""" + var loc = """ +MdDocument: 1,1--1,21 + MdParagraph: 1,1--1,21 + MdText: 1,1--1,3 + MdLink: 1,4--1,20 + MdText: 1,5--1,19 + MdText: 1,21--1,21 +""" + assert md_to_loc(md) == loc + end + + fun test_inline_autolink_bad is test do + var md = """ +An http://autolink>. +""" + var loc = """ +MdDocument: 1,1--1,20 + MdParagraph: 1,1--1,20 + MdText: 1,1--1,20 +""" + assert md_to_loc(md) == loc + end + + fun test_inline_autolink_bad2 is test do + var md = """ +An . +""" + var loc = """ +MdDocument: 1,1--1,21 + MdParagraph: 1,1--1,21 + MdText: 1,1--1,3 + MdLink: 1,4--1,20 + MdText: 1,5--1,19 + MdText: 1,21--1,21 +""" + assert md_to_loc(md) == loc + end + + fun test_inline_link is test do + var md = """ +A [link](url/). +""" + var loc = """ +MdDocument: 1,1--1,15 + MdParagraph: 1,1--1,15 + MdText: 1,1--1,2 + MdLink: 1,3--1,14 + MdText: 1,4--1,7 + MdText: 1,15--1,15 +""" + assert md_to_loc(md) == loc + end + + fun test_inline_link_with_title is test do + var md = """ +A [link](url/ "title"). +""" + var loc = """ +MdDocument: 1,1--1,23 + MdParagraph: 1,1--1,23 + MdText: 1,1--1,2 + MdLink: 1,3--1,22 + MdText: 1,4--1,7 + MdText: 1,23--1,23 +""" + assert md_to_loc(md) == loc + end + + fun test_inline_link_with_content is test do + var md = """ +A [`code` link](url/). +""" + var loc = """ +MdDocument: 1,1--1,22 + MdParagraph: 1,1--1,22 + MdText: 1,1--1,2 + MdLink: 1,3--1,21 + MdCode: 1,4--1,9 + MdText: 1,10--1,14 + MdText: 1,22--1,22 +""" + assert md_to_loc(md) == loc + end + + fun test_inline_link_bad is test do + var md = """ +A [link](url/. +""" + var loc = """ +MdDocument: 1,1--1,14 + MdParagraph: 1,1--1,14 + MdText: 1,1--1,14 +""" + assert md_to_loc(md) == loc + end + + fun test_inline_image is test do + var md = """ +A ![img](url/). +""" + var loc = """ +MdDocument: 1,1--1,15 + MdParagraph: 1,1--1,15 + MdText: 1,1--1,2 + MdImage: 1,3--1,14 + MdText: 1,5--1,7 + MdText: 1,15--1,15 +""" + assert md_to_loc(md) == loc + end + + fun test_inline_image_bad is test do + var md = """ +A ![img](url/. +""" + var loc = """ +MdDocument: 1,1--1,14 + MdParagraph: 1,1--1,14 + MdText: 1,1--1,14 +""" + assert md_to_loc(md) == loc + end + + fun test_inline_link_ref is test do + var md = """ +A [link][]. + +[link]: url/ +""" + var loc = """ +MdDocument: 1,1--1,11 + MdParagraph: 1,1--1,11 + MdText: 1,1--1,2 + MdLink: 1,3--1,10 + MdText: 1,4--1,7 + MdText: 1,11--1,11 +""" + assert md_to_loc(md) == loc + end + + fun test_inline_link_ref2 is test do + var md = """ +A [foo][link]. + +[link]: url/ +""" + var loc = """ +MdDocument: 1,1--1,14 + MdParagraph: 1,1--1,14 + MdText: 1,1--1,2 + MdLink: 1,3--1,13 + MdText: 1,4--1,6 + MdText: 1,14--1,14 +""" + assert md_to_loc(md) == loc + end + + fun test_inline_link_ref_bad is test do + var md = """ +A [foo][link2]. + +[link]: url/ +""" + var loc = """ +MdDocument: 1,1--1,15 + MdParagraph: 1,1--1,15 + MdText: 1,1--1,15 +""" + assert md_to_loc(md) == loc + end + + fun test_inline_html is test do + var md = """ +An
    break line. +""" + var loc = """ +MdDocument: 1,1--1,21 + MdParagraph: 1,1--1,21 + MdText: 1,1--1,3 + MdHtmlInline: 1,4--1,9 + MdText: 1,10--1,21 +""" + assert md_to_loc(md) == loc + end + + + fun test_inline_html2 is test do + var md = """ +An *emph*. +""" + var loc = """ +MdDocument: 1,1--1,29 + MdParagraph: 1,1--1,29 + MdText: 1,1--1,3 + MdHtmlInline: 1,4--1,18 + MdEmphasis: 1,19--1,24 + MdText: 1,20--1,23 + MdHtmlInline: 1,25--1,28 + MdText: 1,29--1,29 +""" + assert md_to_loc(md) == loc + end + + fun test_inline_escape is test do + var md = """ +A text with \\"escaped chars\\". +""" + var loc = """ +MdDocument: 1,1--1,30 + MdParagraph: 1,1--1,30 + MdText: 1,1--1,30 +""" + assert md_to_loc(md) == loc + end + + fun test_inline_soft_break is test do + var md = """ +A text with +a soft break. +""" + var loc = """ +MdDocument: 1,1--2,13 + MdParagraph: 1,1--2,13 + MdText: 1,1--1,11 + MdSoftLineBreak: 1,12--1,12 + MdText: 2,1--2,13 +""" + assert md_to_loc(md) == loc + end + + fun test_inline_soft_break2 is test do + var md = """A text with \na hard break.\n""" + var loc = """ +MdDocument: 1,1--2,13 + MdParagraph: 1,1--2,13 + MdText: 1,1--1,11 + MdSoftLineBreak: 1,12--1,13 + MdText: 2,1--2,13 +""" + assert md_to_loc(md) == loc + end + + fun test_inline_hard_break is test do + var md = """ +A text with\\ +a hard break. +""" + var loc = """ +MdDocument: 1,1--2,13 + MdParagraph: 1,1--2,13 + MdText: 1,1--1,11 + MdHardLineBreak: 1,12--1,13 + MdText: 2,1--2,13 +""" + assert md_to_loc(md) == loc + end + + fun test_inline_hard_break2 is test do + var md = """A text with \na hard break.\n""" + var loc = """ +MdDocument: 1,1--2,13 + MdParagraph: 1,1--2,13 + MdText: 1,1--1,11 + MdHardLineBreak: 1,12--1,14 + MdText: 2,1--2,13 +""" + assert md_to_loc(md) == loc + end +end diff --git a/lib/markdown2/tests/test_markdown_man.nit b/lib/markdown2/tests/test_markdown_man.nit new file mode 100644 index 0000000..e64dd2a --- /dev/null +++ b/lib/markdown2/tests/test_markdown_man.nit @@ -0,0 +1,386 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Tests for markdown rendering to manpage +module test_markdown_man is test + +import test_markdown +import markdown_man_rendering + +# Abstract test class that defines the test methods for Man rendering +abstract class TestMarkdownMan + super TestMarkdown + + # Man renderer used in tests + var man_renderer = new ManRenderer + + # Render the `md` string as Manpage format + fun md_to_man(md: String): String do + var node = parse_md(md) + return man_renderer.render(node) + end +end + +class TestManRendering + super TestMarkdownMan + test + + fun test_headings is test do + var md = """# title1\n## title2\n### title3\n#### title4\n##### title5\n###### title6\n""" + var man = """.SH title1\n.SS title2\n.TP\ntitle3\n.TP\ntitle4\n.TP\ntitle5\n.TP\ntitle6\n""" + assert md_to_man(md) == man + end + + fun test_bquotes is test do + var md = """> line 1\n> line 2\n\n> line 3\n>line 4""" + var man = """.RS\nline 1\nline 2\n.RE\n.RS\nline 3\nline 4\n.RE\n""" + assert md_to_man(md) == man + end + + fun test_breaks is test do + var md = """* * *""" + var man = """***\n""" + assert md_to_man(md) == man + end + + fun test_indented_code is test do + var md = """\tline 1\n\tline 2\n""" + var man = """.RS\n.nf\n\\f[C]\nline\\ 1\nline\\ 2\n\\f[]\n.fi\n.RE\n""" + assert md_to_man(md) == man + end + + fun test_fenced_code is test do + var md = """~~~\nline 1\nline 2\n~~~\n""" + var man = """.RS\n.nf\n\\f[C]\nline\\ 1\nline\\ 2\n\\f[]\n.fi\n.RE\n""" + assert md_to_man(md) == man + end + + fun test_escaped_code is test do + var md = """\tline - 1\n\tline - 2\n""" + var man = """.RS\n.nf\n\\f[C]\nline\\ \\-\\ 1\nline\\ \\-\\ 2\n\\f[]\n.fi\n.RE\n""" + assert md_to_man(md) == man + end + + fun test_unordered_list is test do + var md = """* line 1\n* line 2\n""" + var man = """.RS\n.IP \\[bu] 3\nline 1\n.IP \\[bu] 3\nline 2\n.RE\n""" + assert md_to_man(md) == man + end + + fun test_ordered_list is test do + var md = """2) line 1\n3) line 2\n""" + var man = """.RS\n.IP "2." 3\nline 1\n.IP "3." 3\nline 2\n.RE\n""" + assert md_to_man(md) == man + end + + fun test_paragraph is test do + var md = """line 1\nline 2\n\nline 3\nline 4\n""" + var man = """\nline 1\nline 2\n\nline 3\nline 4\n""" + assert md_to_man(md) == man + end + + fun test_escaped_text is test do + var md = """foo - bar\n""" + var man = """\nfoo \\- bar\n""" + assert md_to_man(md) == man + end + + fun test_inline_code is test do + var md = """`foo - bar`\n""" + var man = """\n\\f[C]foo\\ \\-\\ bar\\f[]\n""" + assert md_to_man(md) == man + end + + fun test_emphasis is test do + var md = """*foo*\n""" + var man = """\n\\f[I]foo\\f[]\n""" + assert md_to_man(md) == man + end + + fun test_strong_emphasis is test do + var md = """**foo**\n""" + var man = """\n\\f[B]foo\\f[]\n""" + assert md_to_man(md) == man + end + + fun test_link is test do + var md = """[foo](url "title")\n""" + var man = """\nfoo (url title)\n""" + assert md_to_man(md) == man + end + + fun test_image is test do + var md = """![foo](url "title")\n""" + var man = """\nfoo (url title)\n""" + assert md_to_man(md) == man + end + + fun test_full_document is test do + + var md = """ +# NAME + +nitdoc - generates HTML pages of API documentation from Nit source files. + +# SYNOPSIS + +nitdoc [*options*]... FILE... + +# DESCRIPTION + +`nitdoc` takes one or more modules and generate HTML pages of API documentation for these modules and their imported modules. + +The documentation is extracted from the comments found above the definition of modules, classes, and properties. + +Internally, `nitdoc` relies on the presence of the `dot` command from the [graphviz] project. +If the dot program is not present or not found, no image of hierarchies are generated. +See option `--no-dot`. + +The documentation of the Nit [standard library] is generated with this tool. + + [graphviz]: http://www.graphviz.org + [standard library]: http://nitlanguage.org/doc/stdlib + +# DOCUMENTATION FORMAT + +The format of the documentation is a dialect of [markdown] that allows GitHub fences (`~~~`). + +Code blocks are interpreted as snippets of Nit programs and intended to be used as examples of code. +When these code snippets are valid, executable and contain at least and `assert` clause, they could be automatically executed and verified. +See `nitunit(1)` for details. + + [markdown]: http://daringfireball.net/projects/markdown + +# OPTIONS + +### `-d`, `--dir` +Output directory. + +Where the HTML files are generated. + +By default, the directory is named `doc`. + +### `--source` +Format to link source code. + +The format string is used to generated links to some parts of the source-code. +Use `%f` for filename, `%l` for first line, and `%L` for last line. + +For instance, the [standard library] use the following value to link to files in GitHub: + + "https://github.com/nitlang/nit/blob/$(git rev-parse HEAD)/%f#L%l-%L" + +Here, the `git rev-parse HEAD` is used to link to the current snapshot revision of the file. + +### `--no-attributes` +Ignore the attributes. + +Note: In Nit, attributes are private. Therefore, this option is only useful +when combined with `--private`. + +### `--no-dot` +Do not generate graphs with graphviz. + +### `--private` +Also generate private API. + +## CUSTOMIZATION + +### `--share-dir` +Directory containing tools assets. + +By default `$NIT_DIR/share/nitdoc/` is used. + +### `--shareurl` +Use shareurl instead of copy shared files. + +By default, assets from the sharedir a copied into the output directory and referred with a relative path in the generated files. +With this option, the assets are not copied and the given URL of path is used in the generated files to locate assets. + +### `--custom-title` +Custom title for homepage. + +### `--custom-footer-text` +Custom footer text. + +### `--custom-overview-text` +Custom intro text for homepage. + +### `--custom-brand` +Custom link to external site. + +## SERVICES + +### `--github-upstream` +Git branch where edited commits will be pulled into (ex: user:repo:branch). + +### `--github-base-sha1` +Git sha1 of base commit used to create pull request. + +### `--github-gitdir` +Git working directory used to resolve path name (ex: /home/me/myproject/). + +### `--piwik-tracker` +Piwik tracker URL (ex: `nitlanguage.org/piwik/`). + +### `--piwik-site-id` +Piwik site ID. + +## TESTING + +### `--test` +Print test data (metrics and structure). + +### `--no-render` +Do not render HTML files. + +# SEE ALSO + +The Nit language documentation and the source code of its tools and libraries may be downloaded from +""" + + var man = """ +.SH NAME + +nitdoc \\- generates HTML pages of API documentation from Nit source files. +.SH SYNOPSIS + +nitdoc [\\f[I]options\\f[]]... FILE... +.SH DESCRIPTION + +\\f[C]nitdoc\\f[] takes one or more modules and generate HTML pages of API documentation for these modules and their imported modules. + +The documentation is extracted from the comments found above the definition of modules, classes, and properties. + +Internally, \\f[C]nitdoc\\f[] relies on the presence of the \\f[C]dot\\f[] command from the graphviz (http://www.graphviz.org) project. +If the dot program is not present or not found, no image of hierarchies are generated. +See option \\f[C]\\-\\-no\\-dot\\f[]. + +The documentation of the Nit standard library (http://nitlanguage.org/doc/stdlib) is generated with this tool. +.SH DOCUMENTATION FORMAT + +The format of the documentation is a dialect of markdown (http://daringfireball.net/projects/markdown) that allows GitHub fences (\\f[C]~~~\\f[]). + +Code blocks are interpreted as snippets of Nit programs and intended to be used as examples of code. +When these code snippets are valid, executable and contain at least and \\f[C]assert\\f[] clause, they could be automatically executed and verified. +See \\f[C]nitunit(1)\\f[] for details. +.SH OPTIONS +.TP +\\f[C]\\-d\\f[], \\f[C]\\-\\-dir\\f[] + +Output directory. + +Where the HTML files are generated. + +By default, the directory is named \\f[C]doc\\f[]. +.TP +\\f[C]\\-\\-source\\f[] + +Format to link source code. + +The format string is used to generated links to some parts of the source\\-code. +Use \\f[C]%f\\f[] for filename, \\f[C]%l\\f[] for first line, and \\f[C]%L\\f[] for last line. + +For instance, the standard library (http://nitlanguage.org/doc/stdlib) use the following value to link to files in GitHub: +.RS +.nf +\\f[C] +"https://github.com/nitlang/nit/blob/$(git\\ rev\\-parse\\ HEAD)/%f#L%l\\-%L" +\\f[] +.fi +.RE + +Here, the \\f[C]git\\ rev\\-parse\\ HEAD\\f[] is used to link to the current snapshot revision of the file. +.TP +\\f[C]\\-\\-no\\-attributes\\f[] + +Ignore the attributes. + +Note: In Nit, attributes are private. Therefore, this option is only useful +when combined with \\f[C]\\-\\-private\\f[]. +.TP +\\f[C]\\-\\-no\\-dot\\f[] + +Do not generate graphs with graphviz. +.TP +\\f[C]\\-\\-private\\f[] + +Also generate private API. +.SS CUSTOMIZATION +.TP +\\f[C]\\-\\-share\\-dir\\f[] + +Directory containing tools assets. + +By default \\f[C]$NIT_DIR/share/nitdoc/\\f[] is used. +.TP +\\f[C]\\-\\-shareurl\\f[] + +Use shareurl instead of copy shared files. + +By default, assets from the sharedir a copied into the output directory and referred with a relative path in the generated files. +With this option, the assets are not copied and the given URL of path is used in the generated files to locate assets. +.TP +\\f[C]\\-\\-custom\\-title\\f[] + +Custom title for homepage. +.TP +\\f[C]\\-\\-custom\\-footer\\-text\\f[] + +Custom footer text. +.TP +\\f[C]\\-\\-custom\\-overview\\-text\\f[] + +Custom intro text for homepage. +.TP +\\f[C]\\-\\-custom\\-brand\\f[] + +Custom link to external site. +.SS SERVICES +.TP +\\f[C]\\-\\-github\\-upstream\\f[] + +Git branch where edited commits will be pulled into (ex: user:repo:branch). +.TP +\\f[C]\\-\\-github\\-base\\-sha1\\f[] + +Git sha1 of base commit used to create pull request. +.TP +\\f[C]\\-\\-github\\-gitdir\\f[] + +Git working directory used to resolve path name (ex: /home/me/myproject/). +.TP +\\f[C]\\-\\-piwik\\-tracker\\f[] + +Piwik tracker URL (ex: \\f[C]nitlanguage.org/piwik/\\f[]). +.TP +\\f[C]\\-\\-piwik\\-site\\-id\\f[] + +Piwik site ID. +.SS TESTING +.TP +\\f[C]\\-\\-test\\f[] + +Print test data (metrics and structure). +.TP +\\f[C]\\-\\-no\\-render\\f[] + +Do not render HTML files. +.SH SEE ALSO + +The Nit language documentation and the source code of its tools and libraries may be downloaded from http://nitlanguage.org (http://nitlanguage.org) +""" + assert md_to_man(md) == man + end +end diff --git a/lib/markdown2/tests/test_markdown_md.nit b/lib/markdown2/tests/test_markdown_md.nit new file mode 100644 index 0000000..6705a2f --- /dev/null +++ b/lib/markdown2/tests/test_markdown_md.nit @@ -0,0 +1,663 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Tests for markdown rendering to markdown +module test_markdown_md is test + +import test_markdown +import markdown_md_rendering + +abstract class TestMarkdownMd + super TestMarkdown + + var md_renderer = new MarkdownRenderer + + fun md_to_md(md: String): String do + var doc = md_parser.parse(md) + doc.debug + return md_renderer.render(doc) + end +end + +class TestMdHeadings + super TestMarkdownMd + test + + fun test_no_trailings is test do + var md = """# foo\n## foo\n### foo\n#### foo\n##### foo\n###### foo\n""" + var exp = """# foo\n\n## foo\n\n### foo\n\n#### foo\n\n##### foo\n\n###### foo\n""" + assert md_to_md(md) == exp + end + + fun test_trailings is test do + var md = """# foo #\n## foo ##\n### foo ###\n#### foo ####\n##### foo #####\n""" + var exp = """# foo #\n\n## foo ##\n\n### foo ###\n\n#### foo ####\n\n##### foo #####\n""" + assert md_to_md(md) == exp + end + + fun test_setext is test do + var md = """Foo *bar*\n=========\nFoo *bar*\n---------\n""" + var exp = """Foo *bar*\n=========\n\nFoo *bar*\n---------\n""" + assert md_to_md(md) == exp + end +end + +class TestMdBlockQuotes + super TestMarkdownMd + test + + fun test191 is test do + var md = """> # Foo\n> bar\n> baz\n""" + assert md_to_md(md) == md + end + + fun test197 is test do + var md = """> foo\n---\n""" + var exp = """> foo\n\n---\n""" + assert md_to_md(md) == exp + end + + fun test198 is test do + var md = """> - foo\n- bar\n""" + var exp = """> - foo\n\n- bar\n""" + assert md_to_md(md) == exp + end + + fun test206 is test do + var md = """> foo\n> bar\n""" + assert md_to_md(md) == md + end + + fun test213 is test do + var md = """> > > foo\n> bar\n""" + var exp = """> > > foo\n> > > bar\n""" + assert md_to_md(md) == exp + end +end + +class TestMdLists + super TestMarkdownMd + test + + fun test264 is test do + var md = """- foo\n- bar\n+ baz\n""" + var exp = """- foo\n- bar\n\n+ baz\n""" + assert md_to_md(md) == exp + end + + fun test265 is test do + var md = """1. foo\n2. bar\n3) baz\n""" + var exp = """1. foo\n2. bar\n\n3) baz\n""" + assert md_to_md(md) == exp + end + + fun test270 is test do + var md = """- foo\n - bar\n - baz\n\n bim\n""" + assert md_to_md(md) == md + end + + fun test273 is test do + var md = """- a\n - b\n - c\n - d\n - e\n - f\n- g\n""" + var exp = """- a\n- b\n- c\n- d\n- e\n- f\n- g\n""" + assert md_to_md(md) == exp + end + + fun test274 is test do + var md = """1. a\n\n 2. b\n\n 3. c\n""" + var exp = """1. a\n\n2. b\n\n3. c\n""" + assert md_to_md(md) == exp + end + + fun test289 is test do + var md = """- a\n - b\n - c\n\n- d\n - e\n - f\n""" + var exp = """- a\n\n - b\n - c\n\n- d\n\n - e\n - f\n""" + assert md_to_md(md) == exp + end +end + +class TestMdkListItems + super TestMarkdownMd + test + + fun test217 is test do + var md = """1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n""" + var exp = """1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n""" + assert md_to_md(md) == exp + end + + fun test219 is test do + var md = """- one\n\n two\n""" + assert md_to_md(md) == md + end + + fun test221 is test do + var md = """ - one\n\n two\n""" + var exp = """- one\n\n two\n""" + assert md_to_md(md) == exp + end + + # FIXME + # fun test223 is test do + # var md = """>>- one\n>>\n > > two\n""" + # var exp = """> > - one\n> >\n> > two\n""" + # assert md_to_md(md) == exp + # end + + fun test225 is test do + var md = """- foo\n\n bar\n""" + assert md_to_md(md) == md + end + + fun test228 is test do + var md = """123456789. ok\n""" + assert md_to_md(md) == md + end + + fun test230 is test do + var md = """0. ok\n""" + assert md_to_md(md) == md + end + + fun test246 is test do + var md = """1. foo\n2.\n3. bar\n""" + assert md_to_md(md) == md + end + + fun test254 is test do + var md = """ 1. A paragraph\n with two lines.\n""" + var exp = """1. A paragraph\n with two lines.\n""" + assert md_to_md(md) == exp + end + + # FIXME + # fun test255 is test do + # var md = """> 1. > Blockquote\n> continued here.\n""" + # var exp = """> 1. > Blockquote\n > continued here.\n""" + # assert md_to_md(md) == exp + # end +end + +class TestMdFencedCodeBlocks + super TestMarkdownMd + test + + fun test88 is test do + var md = """```\nfoo\n```\n""" + assert md_to_md(md) == md + end + + fun test92 is test do + var md = """~~~\nfoo\n~~~\n""" + assert md_to_md(md) == md + end + + fun test111 is test do + var md = """```ruby\ndef foo(x)\n return 3\nend\n```\n""" + assert md_to_md(md) == md + end + + fun test112 is test do + var md = """~~~~~~\nSome markdown:\n~~~\n**hello**\n~~~\n~~~~~~\n""" + assert md_to_md(md) == md + end +end + +class TestMdIndentedCodeBlocks + super TestMarkdownMd + test + + fun test75 is test do + var md = """ a code block\n""" + assert md_to_md(md) == md + end + + fun test76 is test do + var md = """ a simple\n indented code block\n""" + assert md_to_md(md) == md + end + + fun test80 is test do + var md = """ chunk1\n\n chunk2\n \n \n \n chunk3\n""" + assert md_to_md(md) == """ chunk1\n\n chunk2\n\n\n\n chunk3\n""" + end + + fun test85 is test do + var md = """ foo\n bar\n""" + assert md_to_md(md) == md + end + + fun test87 is test do + var md = """\t\tfoo \n""" + assert md_to_md(md) == md + end +end + +class TestMdThematicBreaks + super TestMarkdownMd + test + + fun test13 is test do + var md = """***\n---\n___\n""" + var exp = """***\n\n---\n\n___\n""" + assert md_to_md(md) == exp + end + + fun test17 is test do + var md = """ ***\n ***\n ***\n""" + var exp = """***\n\n***\n\n***\n""" + assert md_to_md(md) == exp + end + + fun test20 is test do + var md = """_____________________________________\n""" + assert md_to_md(md) == md + end + + fun test21 is test do + var md = """ - - -\n""" + var exp = """- - -\n""" + assert md_to_md(md) == exp + end + + fun test22 is test do + var md = """ ** * ** * ** * **\n""" + var exp = """** * ** * ** * **\n""" + assert md_to_md(md) == exp + end + + fun test23 is test do + var md = """- - - -\n""" + assert md_to_md(md) == md + end +end + +class TestMdParagraphs + super TestMarkdownMd + test + + fun test182 is test do + var md = """aaa\n\nbbb\n""" + assert md_to_md(md) == md + end + + fun test183 is test do + var md = """aaa\nbbb\n\nccc\nddd\n""" + assert md_to_md(md) == md + end + + fun test186 is test do + var md = """aaa\n bbb\n ccc\n""" + var exp = """aaa\nbbb\nccc\n""" + assert md_to_md(md) == exp + end + + fun test187 is test do + var md = """ aaa\nbbb\n""" + var exp = """aaa\nbbb\n""" + assert md_to_md(md) == exp + end +end + +class TestMdHTMLBlocks + super TestMarkdownMd + test + + fun test116 is test do + var md = """
    \n
    \n*Hello*,\n\n_world_.\n
    \n\n
    \n""" + assert md_to_md(md) == md + end + + fun test119 is test do + var md = """
    \n*foo*\n""" + assert md_to_md(md) == md + end + + fun test120 is test do + var md = """
    \n\n*Markdown*\n\n
    \n""" + assert md_to_md(md) == md + end + + fun test121 is test do + var md = """
    \n
    \n""" + assert md_to_md(md) == md + end + + fun test124 is test do + var md = """
    \nimport Text.HTML.TagSoup\n\nmain :: IO ()\nmain = print $ parseTags tags\n\n""" + assert md_to_md(md) == md + end + + fun test138 is test do + var md = """\n""" + assert md_to_md(md) == md + end + + fun test139 is test do + var md = """\nh1 {color:red;}\n\np {color:blue;}\n\n""" + assert md_to_md(md) == md + end + + fun test149 is test do + var md = """\n""" + assert md_to_md(md) == md + end + + fun test150 is test do + var md = """ \n\n \n""" + assert md_to_md(md) == md + end +end + +# Inlines + +class TestMdLinks + super TestMarkdownMd + test + + fun test_autolink is test do + var md = """\n""" + assert md_to_md(md) == md + end + + fun test_automail is test do + var md = """\n""" + assert md_to_md(md) == md + end + + fun test462 is test do + var md = """[link](/uri "title")\n""" + assert md_to_md(md) == md + end + + fun test463 is test do + var md = """[link](/uri)\n""" + assert md_to_md(md) == md + end + + fun test464 is test do + var md = """[link]()\n""" + assert md_to_md(md) == md + end + + fun test467 is test do + var md = """[link]()\n""" + assert md_to_md(md) == md + end + + fun test483 is test do + var md = """[link](/url 'title "and" title')\n""" + assert md_to_md(md) == """[link](/url "title \\"and\\" title")\n""" + end + + fun test490 is test do + var md = """[link *foo **bar** `#`*](/uri)\n""" + assert md_to_md(md) == md + end +end + +class TestMdImages + super TestMarkdownMd + test + + fun test546 is test do + var md = """![foo](/url "title")\n""" + assert md_to_md(md) == md + end + + fun test552 is test do + var md = """![foo](train.jpg)\n""" + assert md_to_md(md) == md + end + + fun test554 is test do + var md = """![foo]()\n""" + assert md_to_md(md) == md + end + + fun test555 is test do + var md = """![foo](train.jpg)\n""" + assert md_to_md(md) == md + end +end + +class TestMdCodeSpans + super TestMarkdownMd + test + + fun test316 is test do + var md = """`foo`\n""" + assert md_to_md(md) == md + end + + fun test319 is test do + var md = """``foo``\n""" + assert md_to_md(md) == md + end + + fun test332 is test do + var md = """`foo``bar``\n""" + assert md_to_md(md) == md + end +end + +class TestMdEmphasisAndStrongEmphasis + super TestMarkdownMd + test + + fun test333 is test do + var md = """*foo bar*\n""" + assert md_to_md(md) == md + end + + fun test335 is test do + var md = """a*"foo"*\n""" + assert md_to_md(md) == md + end + + fun test336 is test do + var md = """* a *\n""" + assert md_to_md(md) == md + end + + fun test351 is test do + var md = """*(*foo*)*\n""" + assert md_to_md(md) == md + end + + fun test360 is test do + var md = """**foo bar**\n""" + assert md_to_md(md) == md + end + + fun test361 is test do + var md = """** foo bar**\n""" + assert md_to_md(md) == md + end + + fun test364 is test do + var md = """__foo bar__\n""" + assert md_to_md(md) == md + end + + fun test393 is test do + var md = """*foo**bar**baz*\n""" + assert md_to_md(md) == md + end +end + +class TestMdLineBreaks + super TestMarkdownMd + test + + fun test609 is test do + var md = """foo\\\nbaz\n""" + assert md_to_md(md) == md + end + + fun test612 is test do + var md = """foo\\\n bar\n""" + var exp = """foo\\\nbar\n""" + assert md_to_md(md) == exp + end + + fun test613 is test do + var md = """*foo \nbar*\n""" + assert md_to_md(md) == md + end + + fun test619 is test do + var md = """foo\\\n""" + assert md_to_md(md) == md + end + + fun test623 is test do + var md = """foo\nbaz\n""" + assert md_to_md(md) == md + end +end + +class TestMdRawHTML + super TestMarkdownMd + test + + fun test590 is test do + var md = """\n""" + assert md_to_md(md) == md + end + + fun test591 is test do + var md = """Foo \n""" + assert md_to_md(md) == md + end + + fun test596 is test do + var md = """\n""" + assert md_to_md(md) == md + end + + fun test599 is test do + var md = """foo \n""" + assert md_to_md(md) == md + end + + fun test601 is test do + var md = """foo foo -->\n\nfoo \n""" + assert md_to_md(md) == md + end + + fun test602 is test do + var md = """foo \n""" + assert md_to_md(md) == md + end + + fun test604 is test do + var md = """foo &<]]>\n""" + assert md_to_md(md) == md + end + + fun test606 is test do + var md = """foo \n""" + assert md_to_md(md) == md + end +end + +class TestMdTabs + super TestMarkdownMd + test + + fun test1 is test do + var md = """\tfoo\tbaz\t\tbim\n""" + assert md_to_md(md) == md + end + + fun test2 is test do + var md = """ \tfoo\tbaz\t\tbim\n""" + var exp = """ foo\tbaz\t\tbim\n""" + assert md_to_md(md) == exp + end + + fun test3 is test do + var md = """ a\ta\n ὐ\ta\n""" + assert md_to_md(md) == md + end + + fun test4 is test do + var md = """ - foo\n\n\tbar\n""" + var exp = """- foo\n\n bar\n""" + assert md_to_md(md) == exp + end + + fun test8 is test do + var md = """ foo\n\tbar\n""" + var exp = """ foo\n bar\n""" + assert md_to_md(md) == exp + end + + fun test9 is test do + var md = """ - foo\n - bar\n\t - baz\n""" + var exp = """- foo\n - bar\n - baz\n""" + assert md_to_md(md) == exp + end + + fun test10 is test do + var md = """#\tFoo\n""" + var exp = """# Foo\n""" + assert md_to_md(md) == exp + end + + fun test11 is test do + var md = """*\t*\t*\t\n""" + assert md_to_md(md) == md + end +end + +class TestMdBackslashEscapes + super TestMarkdownMd + test + + fun test292 is test do + var md = """\\\t\\A\\a\\ \\3\\φ\\«\n""" + assert md_to_md(md) == md + end + + fun test295 is test do + var md = """foo\\\nbar\n""" + assert md_to_md(md) == md + end + + fun test297 is test do + var md = """ \\[\\]\n""" + assert md_to_md(md) == md + end + + fun test298 is test do + var md = """~~~\n\\[\\]\n~~~\n""" + assert md_to_md(md) == md + end + + fun test299 is test do + var md = """\n""" + assert md_to_md(md) == md + end + + fun test300 is test do + var md = """\n""" + assert md_to_md(md) == md + end +end diff --git a/lib/markdown2/tests/test_markdown_wikilinks.nit b/lib/markdown2/tests/test_markdown_wikilinks.nit new file mode 100644 index 0000000..8721e14 --- /dev/null +++ b/lib/markdown2/tests/test_markdown_wikilinks.nit @@ -0,0 +1,180 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Tests for markdown Wikilinks mode +module test_markdown_wikilinks is test + +import test_markdown +import test_markdown_location +import test_markdown_md +import test_markdown_man +import test_markdown_latex + +redef class TestMarkdown + redef var md_parser do + var parser = super + parser.wikilinks_mode = true + return parser + end +end + +class TestWikilinksLocation + super TestMarkdownLocation + test + + fun test_wikilinks1 is test do + var md = """ +A [[wiki link]] and text. +""" + var loc = """ +MdDocument: 1,1--1,25 + MdParagraph: 1,1--1,25 + MdText: 1,1--1,2 + MdWikilink: 1,3--1,15 + MdText: 1,5--1,13 + MdText: 1,16--1,25 +""" + assert md_to_loc(md) == loc + end + + fun test_wikilinks2 is test do + var md = """ +A [[wiki: link | with: more, args: end]] and text. +""" + var loc = """ +MdDocument: 1,1--1,50 + MdParagraph: 1,1--1,50 + MdText: 1,1--1,2 + MdWikilink: 1,3--1,40 + MdText: 1,5--1,38 + MdText: 1,41--1,50 +""" + assert md_to_loc(md) == loc + end + +end + +class TestWikilinksHtml + super TestMarkdownHtml + test + + fun test_wikilinks1 is test do + var md = """[[foo]]\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test_wikilinks2 is test do + var md = """[[foo | bar baz]]\n""" + var html = """

    foo

    \n""" + assert md_to_html(md) == html + end + + fun test_wikilinks3 is test do + var md = """This is a [[link]] and this is another [[one]].\n""" + var html = """

    This is a link and this is another one.

    \n""" + assert md_to_html(md) == html + end + + fun test_wikilinks4 is test do + var md = """[[very: complex | link: with, more: options]]\n""" + var html = """

    very: complex

    \n""" + assert md_to_html(md) == html + end + + fun test_wikilink_bad1 is test do + var md = """Not a [wikilink]].\n""" + var html = """

    Not a [wikilink]].

    \n""" + assert md_to_html(md) == html + end + + fun test_wikilink_bad2 is test do + var md = """Not a [[wikilink].\n""" + var html = """

    Not a [[wikilink].

    \n""" + assert md_to_html(md) == html + end + + fun test_wikilink_bad3 is test do + var md = """Not a ![[wikilink]].\n""" + var html = """

    Not a ![[wikilink]].

    \n""" + assert md_to_html(md) == html + end + + fun test_wikilink_bad4 is test do + var md = """Not a [wikilink].\n""" + var html = """

    Not a [wikilink].

    \n""" + assert md_to_html(md) == html + end + + fun test_link is test do + var md = """A standard [link](url).\n""" + var html = """

    A standard link.

    \n""" + assert md_to_html(md) == html + end + + fun test_image is test do + var md = """A standard ![image](url).\n""" + var html = """

    A standard image.

    \n""" + assert md_to_html(md) == html + end + + fun test_link_ref1 is test do + var md = """A standard [link definition].\n\n[link definition]: url\n""" + var html = """

    A standard link definition.

    \n""" + assert md_to_html(md) == html + end + + fun test_link_ref2 is test do + var md = """[[wikilinks]] are not \n\n[[link definition]]: url\n""" + var html = """

    wikilinks are not

    \n

    link definition: url

    \n""" + assert md_to_html(md) == html + end +end + +class TestWikilinksMd + super TestMarkdownMd + test + + fun test_wikilinks_md1 is test do + var md = """[[foo]]\n""" + assert md_to_md(md) == md + end + + fun test_wikilinks_md2 is test do + var md = """[[foo: bar | baz: b, c: d]]\n""" + assert md_to_md(md) == md + end +end + +class TestWikilinksMan + super TestMarkdownMan + test + + fun test_wikilinks_man is test do + var md = """[[foo]]\n""" + var man = """\n(foo)\n""" + assert md_to_man(md) == man + end +end + +class TestWikilinksLatex + super TestMarkdownLatex + test + + fun test_wikilinks_latex is test do + var md = """[[foo]]\n""" + var tex = """\\texttt{foo}\n""" + assert md_to_tex(md) == tex + end +end diff --git a/lib/msgpack/ext.nit b/lib/msgpack/ext.nit index 327dbff..909b423 100644 --- a/lib/msgpack/ext.nit +++ b/lib/msgpack/ext.nit @@ -22,12 +22,12 @@ class MsgPackExt serialize # Custom type code, in [0..127] - var typ: Byte + var typ: Int # Data bytes var data: Bytes redef fun hash do return typ.hash + data.hash*8 redef fun ==(o) do return o isa MsgPackExt and o.typ == typ and o.data == data - redef fun to_s do return "<{class_name} typ: {typ}, data: {data.chexdigest}>" + redef fun to_s do return "<{class_name} typ: {typ.to_b}, data: {data.chexdigest}>" end diff --git a/lib/msgpack/msgpack.nit b/lib/msgpack/msgpack.nit index 929c330..84f5f79 100644 --- a/lib/msgpack/msgpack.nit +++ b/lib/msgpack/msgpack.nit @@ -107,7 +107,7 @@ # # ~~~ # assert 0x01u8.serialize_msgpack == b"\xD4\x7E\x01" -# assert b"\xD4\x7E\x01".deserialize_msgpack == 0x01u8 +# assert b"\xD4\x7E\x01".deserialize_msgpack == 1 # ~~~ # # ## Full objects diff --git a/lib/msgpack/read.nit b/lib/msgpack/read.nit index 3b8854a..be68898 100644 --- a/lib/msgpack/read.nit +++ b/lib/msgpack/read.nit @@ -45,7 +45,7 @@ redef class Reader else if typ & 0b1000_0000 == 0 or typ & 0b1110_0000 == 0b1110_0000 then # fixint var bytes = new Bytes.with_capacity(1) - bytes.add typ.to_b + bytes.add typ return bytes.to_i(signed=true) else if typ & 0b1111_0000 == 0b1000_0000 then @@ -174,7 +174,7 @@ redef class Reader # var reader = new BytesReader(b"\xC7\x03\x0A\x0B\x0C\x0D") # var ext = reader.read_msgpack # assert ext isa MsgPackExt - # assert ext.typ == 0x0Au8 + # assert ext.typ == 0x0a # assert ext.data == b"\x0B\x0C\x0D" # ~~~ private fun read_msgpack_fixext_data(len: Int): MsgPackExt @@ -182,7 +182,7 @@ redef class Reader var exttyp = read_byte if exttyp < 0 then exttyp = 0 var data = read_bytes(len) - return new MsgPackExt(exttyp.to_b, data) + return new MsgPackExt(exttyp, data) end # Read the content of a dynamic *ext* including the length on `len_len` bytes diff --git a/lib/msgpack/serialization_common.nit b/lib/msgpack/serialization_common.nit index a9e9ddf..edf9210 100644 --- a/lib/msgpack/serialization_common.nit +++ b/lib/msgpack/serialization_common.nit @@ -19,14 +19,14 @@ module serialization_common abstract class MsgPackEngine # *ext type* byte for object definitions, defaults to 0x7Bu8 or '{' - var ext_typ_obj: Byte = 0x7Bu8 is writable + var ext_typ_obj: Int = 0x7B is writable # *ext type* byte for object references, defaults to 0x7Du8 or '}' - var ext_typ_ref: Byte = 0x7Du8 is writable + var ext_typ_ref: Int = 0x7D is writable # *ext type* byte to identify a char, defaults to 0x7Cu8 or '~' - var ext_typ_char: Byte = 0x7Cu8 is writable + var ext_typ_char: Int = 0x7C is writable # *ext type* byte to identify a byte, defaults to 0x7Eu8 or '|' - var ext_typ_byte: Byte = 0x7Eu8 is writable + var ext_typ_byte: Int = 0x7E is writable end diff --git a/lib/msgpack/serialization_write.nit b/lib/msgpack/serialization_write.nit index 0b5b4f9..e1bb2d0 100644 --- a/lib/msgpack/serialization_write.nit +++ b/lib/msgpack/serialization_write.nit @@ -266,7 +266,7 @@ redef class Byte else # Write as ext var bytes = new Bytes.with_capacity(1) - bytes.add self + bytes.add self.to_i v.stream.write_msgpack_ext(v.ext_typ_byte, bytes) end end diff --git a/lib/msgpack/write.nit b/lib/msgpack/write.nit index 15e5985..7d18e32 100644 --- a/lib/msgpack/write.nit +++ b/lib/msgpack/write.nit @@ -20,11 +20,11 @@ import binary redef class Writer # Write `null`, or nil, in MessagePack format - fun write_msgpack_null do write_byte 0xC0u8 + fun write_msgpack_null do write_byte 0xC0 # Write `bool` in MessagePack format fun write_msgpack_bool(bool: Bool) - do write_byte(if bool then 0xC3u8 else 0xC2u8) + do write_byte(if bool then 0xC3 else 0xC2) # --- # Integers @@ -61,7 +61,7 @@ redef class Writer fun write_msgpack_fixint(value: Int) do assert value >= -0x20 and value <= 0x7F - write_byte value.to_b + write_byte value end # Write `value` over one unsigned byte, following 1 metadata byte @@ -69,7 +69,7 @@ redef class Writer # Require: `value >= 0x00 and value <= 0xFF` fun write_msgpack_uint8(value: Int) do - write_byte 0xCCu8 + write_byte 0xCC write_bytes value.to_bytes(n_bytes=1) end @@ -78,7 +78,7 @@ redef class Writer # Require: `value >= 0x00 and value <= 0xFFFF` fun write_msgpack_uint16(value: Int) do - write_byte 0xCDu8 + write_byte 0xCD write_bytes value.to_bytes(n_bytes=2) end @@ -87,7 +87,7 @@ redef class Writer # Require: `value >= 0x00 and value <= 0xFFFF_FFFF` fun write_msgpack_uint32(value: Int) do - write_byte 0xCEu8 + write_byte 0xCE write_bytes value.to_bytes(n_bytes=4) end @@ -96,7 +96,7 @@ redef class Writer # Require: `value >= 0x00 and value <= 0xFFFF_FFFF_FFFF_FFFF` fun write_msgpack_uint64(value: Int) do - write_byte 0xCFu8 + write_byte 0xCF write_bytes value.to_bytes(n_bytes=8) end @@ -105,28 +105,28 @@ redef class Writer # Require: `value >= -128 and value <= 127` fun write_msgpack_int8(value: Int) do - write_byte 0xD0u8 + write_byte 0xD0 write_bytes value.to_bytes(n_bytes=1) end # Write `value` over two signed bytes, following 1 metadata byte fun write_msgpack_int16(value: Int) do - write_byte 0xD1u8 + write_byte 0xD1 write_bytes value.to_bytes(n_bytes=2) end # Write `value` over 4 signed bytes, following 1 metadata byte fun write_msgpack_int32(value: Int) do - write_byte 0xD2u8 + write_byte 0xD2 write_bytes value.to_bytes(n_bytes=4) end # Write `value` over 8 signed bytes, following 1 metadata byte fun write_msgpack_int64(value: Int) do - write_byte 0xD3u8 + write_byte 0xD3 write_int64 value end @@ -136,14 +136,14 @@ redef class Writer # Write `value` as a MessagePack float (losing precision) fun write_msgpack_float(value: Float) do - write_byte 0xCAu8 + write_byte 0xCA write_float value end # Write `value` as a MessagePack double fun write_msgpack_double(value: Float) do - write_byte 0xCBu8 + write_byte 0xCB write_double value end @@ -177,7 +177,7 @@ redef class Writer var len = text.byte_length assert len <= 0x1F - var b = 0b1010_0000u8 | len.to_b + var b = 0b1010_0000 | len write_byte b write text @@ -191,8 +191,8 @@ redef class Writer var len = text.byte_length assert len <= 0xFF - write_byte 0xD9u8 - write_byte len.to_b + write_byte 0xD9 + write_byte len write text end @@ -204,10 +204,10 @@ redef class Writer var len = text.byte_length assert len <= 0xFFFF - write_byte 0xDAu8 + write_byte 0xDA var len_bytes = len.to_bytes write_byte len_bytes[0] - write_byte if len_bytes.length > 1 then len_bytes[1] else 0u8 + write_byte if len_bytes.length > 1 then len_bytes[1] else 0 write text end @@ -219,11 +219,11 @@ redef class Writer var len = text.byte_length assert len <= 0xFFFF_FFFF - write_byte 0xDBu8 + write_byte 0xDB var len_bytes = len.to_bytes write_byte len_bytes[0] for i in [1..4[ do - write_byte if len_bytes.length > i then len_bytes[i] else 0u8 + write_byte if len_bytes.length > i then len_bytes[i] else 0 end write text end @@ -254,8 +254,8 @@ redef class Writer var len = data.length assert len <= 0xFF - write_byte 0xC4u8 - write_byte len.to_b + write_byte 0xC4 + write_byte len write_bytes data end @@ -267,7 +267,7 @@ redef class Writer var len = data.length assert len <= 0xFFFF - write_byte 0xC5u8 + write_byte 0xC5 write_bytes len.to_bytes(n_bytes=2) write_bytes data end @@ -280,7 +280,7 @@ redef class Writer var len = data.length assert len <= 0xFFFF_FFFF - write_byte 0xC6u8 + write_byte 0xC6 write_bytes len.to_bytes(n_bytes=4) write_bytes data end @@ -314,7 +314,7 @@ redef class Writer fun write_msgpack_fixarray(len: Int) do assert len <= 0x0F - write_byte 0b1001_0000u8 | len.to_b + write_byte 0b1001_0000 | len end # Write an array header for `len` items, max of 0xFFFF items @@ -325,7 +325,7 @@ redef class Writer fun write_msgpack_array16(len: Int) do assert len <= 0xFFFF - write_byte 0xDCu8 + write_byte 0xDC write_bytes len.to_bytes(n_bytes=2) end @@ -337,7 +337,7 @@ redef class Writer fun write_msgpack_array32(len: Int) do assert len <= 0xFFFF_FFFF - write_byte 0xDDu8 + write_byte 0xDD write_bytes len.to_bytes(n_bytes=4) end @@ -372,7 +372,7 @@ redef class Writer fun write_msgpack_fixmap(len: Int) do assert len <= 0x0F - write_byte 0b1000_0000u8 | len.to_b + write_byte 0b1000_0000 | len end # Write a map header for `len` key/value pairs, max of 0xFFFF pairs @@ -384,7 +384,7 @@ redef class Writer fun write_msgpack_map16(len: Int) do assert len <= 0xFFFF - write_byte 0xDEu8 + write_byte 0xDE write_bytes len.to_bytes(n_bytes=2) end @@ -397,7 +397,7 @@ redef class Writer fun write_msgpack_map32(len: Int) do assert len <= 0xFFFF_FFFF - write_byte 0xDFu8 + write_byte 0xDF write_bytes len.to_bytes(n_bytes=4) end @@ -410,10 +410,10 @@ redef class Writer # # ~~~ # var writer = new BytesWriter - # writer.write_msgpack_ext(0x0Au8, b"\x0B\x0C\x0D") + # writer.write_msgpack_ext(0x0A, b"\x0B\x0C\x0D") # assert writer.bytes == b"\xC7\x03\x0A\x0B\x0C\x0D" # ~~~ - fun write_msgpack_ext(typ: Byte, bytes: Bytes) + fun write_msgpack_ext(typ: Int, bytes: Bytes) do var len = bytes.length if len == 1 then @@ -448,45 +448,45 @@ redef class Writer # Write the header for an application-specific extension of one data byte # # After writing the header, clients should write the data byte. - fun write_msgpack_fixext1(typ: Byte) + fun write_msgpack_fixext1(typ: Int) do - write_byte 0xD4u8 + write_byte 0xD4 write_byte typ end # Write the header for an application-specific extension of two data bytes # # After writing the header, clients should write the two data bytes. - fun write_msgpack_fixext2(typ: Byte) + fun write_msgpack_fixext2(typ: Int) do - write_byte 0xD5u8 + write_byte 0xD5 write_byte typ end # Write the header for an application-specific extension of 4 data bytes # # After writing the header, clients should write the 4 data bytes. - fun write_msgpack_fixext4(typ: Byte) + fun write_msgpack_fixext4(typ: Int) do - write_byte 0xD6u8 + write_byte 0xD6 write_byte typ end # Write the header for an application-specific extension of 8 data bytes # # After writing the header, clients should write the 8 data bytes. - fun write_msgpack_fixext8(typ: Byte) + fun write_msgpack_fixext8(typ: Int) do - write_byte 0xD7u8 + write_byte 0xD7 write_byte typ end # Write the header for an application-specific extension of 16 data bytes # # After writing the header, clients should write the 16 data bytes. - fun write_msgpack_fixext16(typ: Byte) + fun write_msgpack_fixext16(typ: Int) do - write_byte 0xD8u8 + write_byte 0xD8 write_byte typ end @@ -495,11 +495,11 @@ redef class Writer # After writing the header, clients should write the data bytes. # # Require: `len >= 0 and <= 0xFF` - fun write_msgpack_ext8(typ: Byte, len: Int) + fun write_msgpack_ext8(typ, len: Int) do assert len >= 0 and len <= 0xFF - write_byte 0xC7u8 - write_byte len.to_b + write_byte 0xC7 + write_byte len write_byte typ end @@ -508,10 +508,10 @@ redef class Writer # After writing the header, clients should write the data bytes. # # Require: `len >= 0 and <= 0xFFFF` - fun write_msgpack_ext16(typ: Byte, len: Int) + fun write_msgpack_ext16(typ, len: Int) do assert len >= 0 and len <= 0xFFFF - write_byte 0xC8u8 + write_byte 0xC8 write_bytes len.to_bytes(n_bytes=2) write_byte typ end @@ -521,10 +521,10 @@ redef class Writer # After writing the header, clients should write the data bytes. # # Require: `len >= 0 and <= 0xFFFF_FFFF` - fun write_msgpack_ext32(typ: Byte, len: Int) + fun write_msgpack_ext32(typ, len: Int) do assert len >= 0 and len <= 0xFFFF_FFFF - write_byte 0xC9u8 + write_byte 0xC9 write_bytes len.to_bytes(n_bytes=4) write_byte typ end diff --git a/lib/nitcorn/file_server.nit b/lib/nitcorn/file_server.nit index a9ef5f6..96293f6 100644 --- a/lib/nitcorn/file_server.nit +++ b/lib/nitcorn/file_server.nit @@ -125,7 +125,7 @@ class FileServer if response.status_code != 200 then var tmpl = error_page(response.status_code) if header != null and tmpl isa ErrorTemplate then tmpl.header = header - response.body = tmpl.to_s + response.body = tmpl end return response diff --git a/lib/nitcorn/http_response.nit b/lib/nitcorn/http_response.nit index ec83289..97276ca 100644 --- a/lib/nitcorn/http_response.nit +++ b/lib/nitcorn/http_response.nit @@ -20,6 +20,7 @@ module http_response import serialization +private import template # A response to send over HTTP class HttpResponse @@ -38,7 +39,7 @@ class HttpResponse var header = new HashMap[String, String] # Body of this response - var body = "" is writable + var body: Writable = "" is writable # Files appended after `body` var files = new Array[String] @@ -49,7 +50,20 @@ class HttpResponse # Set the content length if not already set if not header.keys.has("Content-Length") then # Size of the body - var len = body.byte_length + var len + var body = self.body + if body isa Text then + len = body.byte_length + else if body isa Bytes then + len = body.length + else + # We need the length, but there is no length in a writable. + # So just render it as a bytes then measure :/ + body = body.write_to_bytes + len = body.length + # Keep the body as bytes since we have it + self.body = body + end # Size of included files for path in files do @@ -77,17 +91,18 @@ class HttpResponse end # Get this reponse as a string according to HTTP protocol - redef fun to_s + fun render: Writable do finalize - var buf = new FlatBuffer - buf.append("{http_version} {status_code} {status_message or else ""}\r\n") + var buf = new Template + buf.add("{http_version} {status_code} {status_message or else ""}\r\n") for key, value in header do - buf.append("{key}: {value}\r\n") + buf.add("{key}: {value}\r\n") end - buf.append("\r\n{body}") - return buf.to_s + buf.add("\r\n") + buf.add body + return buf end end diff --git a/lib/nitcorn/reactor.nit b/lib/nitcorn/reactor.nit index afa0d0a..def3699 100644 --- a/lib/nitcorn/reactor.nit +++ b/lib/nitcorn/reactor.nit @@ -91,7 +91,7 @@ class HttpServer # Send back `response` to the client fun respond(response: HttpResponse) do - write response.to_s + response.render.write_to(self) for path in response.files do write_file path end end @@ -176,7 +176,7 @@ redef class Sys var listener = listeners[name, port] if listener == null then - listener = factory.bind_to(name, port) + listener = factory.bind_tcp(name, port) if listener != null then sys.listeners[name, port] = listener listeners_count[name, port] = 1 diff --git a/lib/nitcorn/token.nit b/lib/nitcorn/token.nit index 31aefd6..7e55f69 100644 --- a/lib/nitcorn/token.nit +++ b/lib/nitcorn/token.nit @@ -58,7 +58,7 @@ do # Fallback if bytes == null or bytes.length != bin_length or force_rand == true then bytes = new Bytes.with_capacity(bin_length) - for i in bin_length.times do bytes.add 256.rand.to_b + for i in bin_length.times do bytes.add 256.rand end # Encode in base64 so it is readable diff --git a/lib/perfect_hashing/perfect_hashing.nit b/lib/perfect_hashing/perfect_hashing.nit index d8ab3cb..585130e 100644 --- a/lib/perfect_hashing/perfect_hashing.nit +++ b/lib/perfect_hashing/perfect_hashing.nit @@ -101,6 +101,7 @@ class Perfecthashing # n : number of required free identifiers # idc : This array will be filled with n free identifiers # return the size of hashTable to create for theses identifiers (mask + 1) + # # var ph = new Perfecthashing # var idc = new Array[Int] # assert ph.pnand([3, 7, 10], 1, idc) == 6 diff --git a/lib/popcorn/pop_handlers.nit b/lib/popcorn/pop_handlers.nit index e657d68..cd7a380 100644 --- a/lib/popcorn/pop_handlers.nit +++ b/lib/popcorn/pop_handlers.nit @@ -431,7 +431,7 @@ redef class HttpResponse # Write data in body response and send it. fun send(raw_data: nullable Writable, status: nullable Int) do if raw_data != null then - body += raw_data.write_to_string + body = raw_data end if status != null then status_code = status diff --git a/lib/posix/README.md b/lib/posix/README.md new file mode 100644 index 0000000..3b73f9c --- /dev/null +++ b/lib/posix/README.md @@ -0,0 +1,5 @@ +Services conforming to POSIX + +The core module `posix` includes POSIX services available on all POSIX compliant systems. +For services provided by some implementations of POSIX but absent from any POSIX version, +import `posix::ext`. diff --git a/lib/posix_ext/posix_ext.nit b/lib/posix/ext.nit similarity index 91% rename from lib/posix_ext/posix_ext.nit rename to lib/posix/ext.nit index 8dd83c3..85da40a 100644 --- a/lib/posix_ext/posix_ext.nit +++ b/lib/posix/ext.nit @@ -1,7 +1,5 @@ # This file is part of NIT ( http://www.nitlanguage.org ). # -# Copyright 2014 Alexis Laferrière -# # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -15,7 +13,9 @@ # limitations under the License. # Services not defined in POSIX but provided by most implementations -module posix_ext +module ext + +import posix redef extern class Passwd # User information diff --git a/lib/posix_ext/package.ini b/lib/posix/package.ini similarity index 55% rename from lib/posix_ext/package.ini rename to lib/posix/package.ini index 6b78527..79c6ca1 100644 --- a/lib/posix_ext/package.ini +++ b/lib/posix/package.ini @@ -1,12 +1,12 @@ [package] -name=posix_ext +name=posix tags=wrapper,lib maintainer=Alexis Laferrière license=Apache-2.0 -desc=Services not defined in POSIX but provided by most implementations +desc=Services conforming to POSIX [upstream] -browse=https://github.com/nitlang/nit/tree/master/lib/posix_ext/ +browse=https://github.com/nitlang/nit/tree/master/lib/posix/ git=https://github.com/nitlang/nit.git -git.directory=lib/posix_ext/ +git.directory=lib/posix/ homepage=http://nitlanguage.org issues=https://github.com/nitlang/nit/issues diff --git a/lib/core/posix.nit b/lib/posix/posix.nit similarity index 94% rename from lib/core/posix.nit rename to lib/posix/posix.nit index 587e606..03a8a2e 100644 --- a/lib/core/posix.nit +++ b/lib/posix/posix.nit @@ -1,7 +1,5 @@ # This file is part of NIT ( http://www.nitlanguage.org ). # -# Copyright 2013 Alexis Laferrière -# # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -17,8 +15,6 @@ # Services conforming to POSIX module posix -import text - in "C Header" `{ #include #include @@ -111,8 +107,3 @@ extern class Group `{struct group*`} return ret; `} end - -redef class Int - # Does the file descriptor `self` refer to a terminal? - fun isatty: Bool `{ return isatty(self); `} -end diff --git a/lib/privileges/privileges.nit b/lib/privileges/privileges.nit index f17a28e..c3a9466 100644 --- a/lib/privileges/privileges.nit +++ b/lib/privileges/privileges.nit @@ -21,6 +21,7 @@ module privileges import opts +import posix redef class Text # Does the operating system know the user named `self`? diff --git a/lib/sha1/sha1.nit b/lib/sha1/sha1.nit index a80e9f2..6ad30c8 100644 --- a/lib/sha1/sha1.nit +++ b/lib/sha1/sha1.nit @@ -245,7 +245,7 @@ redef class Text # sha1_hexdigest. # # import base64 - # assert "The quick brown fox jumps over the lazy dog".sha1 == [0x2Fu8, 0xD4u8, 0xE1u8, 0xC6u8, 0x7Au8, 0x2Du8, 0x28u8, 0xFCu8, 0xEDu8, 0x84u8, 0x9Eu8, 0xE1u8, 0xBBu8, 0x76u8, 0xE7u8, 0x39u8, 0x1Bu8, 0x93u8, 0xEBu8, 0x12u8] + # assert "The quick brown fox jumps over the lazy dog".sha1 == [0x2F, 0xD4, 0xE1, 0xC6, 0x7A, 0x2D, 0x28, 0xFC, 0xED, 0x84, 0x9E, 0xE1, 0xBB, 0x76, 0xE7, 0x39, 0x1B, 0x93, 0xEB, 0x12] fun sha1: Bytes do return new Bytes(to_cstring.sha1_intern(byte_length), 20, 20) end diff --git a/lib/socket/socket_c.nit b/lib/socket/socket_c.nit index e359b77..13b4049 100644 --- a/lib/socket/socket_c.nit +++ b/lib/socket/socket_c.nit @@ -141,7 +141,7 @@ extern class NativeSocket `{ int* `} `} # Write `value` as a single byte - fun write_byte(value: Byte): Int `{ + fun write_byte(value: Int): Int `{ unsigned char byt = (unsigned char)value; return write(*self, &byt, 1); `} diff --git a/lib/trees/bintree.nit b/lib/trees/bintree.nit index 610ec2e..447a33f 100644 --- a/lib/trees/bintree.nit +++ b/lib/trees/bintree.nit @@ -36,6 +36,7 @@ import abstract_tree # * delete average O(lg n) worst O(n) # # Usage: +# # var tree = new BinTreeMap[Int, String] # tree[1] = "n1" # assert tree.min == "n1" diff --git a/lib/trees/bktree.nit b/lib/trees/bktree.nit new file mode 100644 index 0000000..b7d0d48 --- /dev/null +++ b/lib/trees/bktree.nit @@ -0,0 +1,149 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Implementation of BKTree +# +# As proposed by W. A. Burkhard and R. M. Keller in +# "Some approaches to best-match file searching" the BKTree data structure +# is usefull to speed-up spell checking based on the Levenshtein distance between +# words. +# +# With a BKTree, the complexity to find mispelled words in a dictionnary is *O(log n)* +# instead of *O(n)* with a dummy list. +# +# Example: +# +# ~~~ +# # Create a new BKTree +# var tree = new BKTree +# +# # Index some words in the dictionnary for spell checking +# tree.add("book") +# tree.add("books") +# tree.add("cake") +# tree.add("boo") +# tree.add("cape") +# tree.add("boon") +# tree.add("cook") +# tree.add("cart") +# +# # Search suggestions in the BKTree +# assert tree.search("caqe").join(", ") == "\{1: cake\}, \{1: cape\}" +# ~~~ +# +# See . +module bktree + +import abstract_tree + +# A BKTree implementation +# +# See `add` to insert a new word. +# See `search` to find matches from a `key`. +class BKTree + + # Default tolerance used to find matches + # + # Default is `2`. + var default_tolerance = 2 is writable + + # Tree root + private var root: nullable BKNode = null + + # Add a `key` in the tree + fun add(key: String) do + var root = self.root + if root == null then + self.root = new BKNode(key) + return + end + + var node = root + var dist = node.key.levenshtein_distance(key) + + while node.has_key(dist) do + if dist == 0 then return + node = node[dist] + dist = node.key.levenshtein_distance(key) + end + node[dist] = new BKNode(key) + end + + # Search `key` with a distance of `tolerance` in `self`. + # + # If `tolerance` is null, the use `default_tolerance` instead. + fun search(key: String, tolerance: nullable Int): Array[BKMatch] do + var res = new Array[BKMatch] + var root = self.root + if root != null then + if tolerance == null then tolerance = self.default_tolerance + search_recursive(root, res, key, tolerance) + end + default_comparator.sort(res) + return res + end + + private fun search_recursive(node: BKNode, res: Array[BKMatch], key: String, tolerance: Int) do + var dist = node.key.levenshtein_distance(key) + var min = dist - tolerance + var max = dist + tolerance + + if dist < tolerance then + res.add new BKMatch(dist, node.key) + end + + for odist, child in node do + if odist < min or odist > max then continue + search_recursive(child, res, key, tolerance) + end + end +end + +# A node that goes in a BKTree +# +# Each child is mapped from `self` by its distance as an Int. +private class BKNode + super HashMap[Int, BKNode] + + # Key stored in `self` + var key: String + + redef fun to_s do return "\{{key}\}" +end + +# A match in a BKTree +# +# Used to order results returned by `BKTree::search`. +class BKMatch + super Comparable + + redef type OTHER: BKMatch + + # Distance of `key` from the search query + var distance: Int + + # Matched `key` + var key: String + + redef fun ==(o) do return o isa BKMatch and distance == o.distance and key == o.key + + redef fun <=>(o) do + if distance == o.distance then + return key <=> o.key + end + return distance <=> o.distance + end + + redef fun to_s do return "\{{distance}: {key}\}" +end diff --git a/lib/vsm/vsm.nit b/lib/vsm/vsm.nit index 4a64f99..ad3d928 100644 --- a/lib/vsm/vsm.nit +++ b/lib/vsm/vsm.nit @@ -77,6 +77,17 @@ class Vector return super end + # Increment value for `obj` term + # + # If the term isn't already in the vector, the new value is 1.0. + fun inc(obj: nullable Object) do + if has_key(obj) then + self[obj] += 1.0 + else + self[obj] = 1.0 + end + end + # The norm of the vector. # # `||x|| = (x1 ** 2 ... + xn ** 2).sqrt` @@ -112,10 +123,18 @@ end # Documents can then be matched to query vectors. class VSMIndex + # Kind of documents stored in this index + # + # Clients can redefine this type to specialize the index. + type DOC: Document + # Documents index + var documents = new HashSet[DOC] + + # Inversed index # - # TODO use a more efficient representation. - var documents = new HashSet[Document] + # Link documents to existing terms. + var inversed_index = new HashMap[nullable Object, Array[DOC]] # Count for all terms in all indexed documents # @@ -137,12 +156,18 @@ class VSMIndex # # Returns an `IndexMatch` for each indexed document. # Results are ordered by descending similarity. - fun match_vector(query: Vector): Array[IndexMatch] do - var matches = new Array[IndexMatch] + fun match_vector(query: Vector): Array[IndexMatch[DOC]] do + var documents = new HashSet[DOC] + for term, count in query do + if inversed_index.has_key(term) then + documents.add_all inversed_index[term] + end + end + var matches = new Array[IndexMatch[DOC]] for doc in documents do var sim = query.cosine_similarity(doc.tfidf) if sim == 0.0 then continue - matches.add new IndexMatch(doc, sim) + matches.add new IndexMatch[DOC](doc, sim) end sorter.sort(matches) return matches @@ -156,13 +181,13 @@ class VSMIndex # # When processing batch documents, use `auto_update = false` to disable # the auto update of the index. - fun index_document(doc: Document, auto_update: nullable Bool) do + fun index_document(doc: DOC, auto_update: nullable Bool) do for term, count in doc.terms_count do - if not terms_doc_count.has_key(term) then - terms_doc_count[term] = 1.0 - else - terms_doc_count[term] += 1.0 + terms_doc_count.inc(term) + if not inversed_index.has_key(term) then + inversed_index[term] = new Array[DOC] end + inversed_index[term].add doc end documents.add doc if auto_update == null or auto_update then update_index @@ -196,7 +221,7 @@ class StringIndex # Return the Document created. # # See `index_document`. - fun index_string(title, uri, string: String, auto_update: nullable Bool): Document do + fun index_string(title, uri, string: String, auto_update: nullable Bool): DOC do var vector = parse_string(string) var doc = new Document(title, uri, vector) index_document(doc, auto_update) @@ -206,7 +231,7 @@ class StringIndex # Match the `query` string against all indexed documents # # See `match_vector`. - fun match_string(query: String): Array[IndexMatch] do + fun match_string(query: String): Array[IndexMatch[DOC]] do var vector = parse_string(query) var doc = new Document("", "", vector) return match_vector(doc.terms_frequency) @@ -221,12 +246,7 @@ class StringIndex loop var token = reader.read_word if token == "" then break - - if not vector.has_key(token) then - vector[token] = 1.0 - else - vector[token] += 1.0 - end + vector.inc(token) end return vector end @@ -241,7 +261,7 @@ class FileIndex # Return the created document or null if `path` is not accepted by `accept_file`. # # See `index_document`. - fun index_file(path: String, auto_update: nullable Bool): nullable Document do + fun index_file(path: String, auto_update: nullable Bool): nullable DOC do if not accept_file(path) then return null var vector = parse_file(path) var doc = new Document(path, path, vector) @@ -347,17 +367,17 @@ class Document # A high weight in tf–idf is reached by a high term frequency # (in the given document) and a low document frequency of the term in the # whole collection of documents - var tfidf = new Vector + var tfidf: Vector = terms_count is lazy redef fun to_s do return "{title}" end # A match to a `request` in an `Index` -class IndexMatch +class IndexMatch[DOC: Document] super Comparable # Document matching the `request_vector` - var document: Document + var document: DOC # Similarity between the `request` and the `doc`. # @@ -372,7 +392,7 @@ end class IndexMatchSorter super DefaultComparator - redef type COMPARED: IndexMatch + redef type COMPARED: IndexMatch[Document] redef fun compare(a, b) do return b.similarity <=> a.similarity diff --git a/lib/websocket/websocket.nit b/lib/websocket/websocket.nit index c5ea6bb..f1a559a 100644 --- a/lib/websocket/websocket.nit +++ b/lib/websocket/websocket.nit @@ -148,14 +148,14 @@ class WebsocketConnection var ans_buffer = new Bytes.with_capacity(msg.byte_length + 2) # Flag for final frame set to 1 # opcode set to 1 (for text) - ans_buffer.add(129u8) + ans_buffer.add(129) if msg.length < 126 then - ans_buffer.add(msg.length.to_b) + ans_buffer.add(msg.length) end if msg.length >= 126 and msg.length <= 65535 then - ans_buffer.add(126u8) - ans_buffer.add((msg.length >> 8).to_b) - ans_buffer.add(msg.length.to_b) + ans_buffer.add(126) + ans_buffer.add(msg.length >> 8) + ans_buffer.add(msg.length) end msg.append_to_bytes(ans_buffer) return ans_buffer diff --git a/misc/Nit_Compiler.lttng b/misc/Nit_Compiler.lttng new file mode 100644 index 0000000..b21d50a --- /dev/null +++ b/misc/Nit_Compiler.lttng @@ -0,0 +1,69 @@ + + + + Nit_Compiler + + + UST + PER_UID + + + blocking-channel + true + DISCARD + 524288 + 4 + 0 + 0 + MMAP + 0 + 1000000 + 0 + 0 + 0 + + + Nit_Compiler:Object_Instance + true + TRACEPOINT + ALL + + + Nit_Compiler:Object_Destroy + true + TRACEPOINT + ALL + + + + + + + + + JUL + PER_UID + + + + LOG4J + PER_UID + + + + PYTHON + PER_UID + + + + false + + + true + + Put your path here ! + + + + + diff --git a/share/man/nitc.md b/share/man/nitc.md index d29a131..eff6232 100644 --- a/share/man/nitc.md +++ b/share/man/nitc.md @@ -249,7 +249,25 @@ For more debugging-related options, see also `--hardening` and `NIT_GC_OPTION` ### `--trace` Compile with lttng's instrumentation. -Currently add a lttng trace provider and add tracepoint into object instances. +Currently add a lttng trace provider and add tracepoint into object instances and destructions. + +The lttng nit/misc/Nit_Compiler.lttng file is a template that you can use instead of configure channels by yourself. You have to configure the path of the destination tracefile. "your path" + +To create a channel with template : + lttng-sessiond --daemonize + lttng load -i=~/nit/misc/Nit_Compiler.lttng Nit_Compiler +To create a channel without template : + lttng create session_name + lttng enable-event --userspace Nit_Compiler:Object_Instance + lttng enable-event --userspace Nit_Compiler:Object_Destroy +To record some traces : + lttng start + --> run your program + lttng stop +To read some traces : + babeltrace ~/session_name +To destroy your current tracing session : + lttng destroy ## COMPILATION MODES diff --git a/share/man/nitpackage.md b/share/man/nitpackage.md index 122ce85..4a4da91 100644 --- a/share/man/nitpackage.md +++ b/share/man/nitpackage.md @@ -66,6 +66,9 @@ Check manpages files. ### `--gen-man` Generate manpages files. +### `--check-readme` +Check README.md files. + ### `-f`, `--force` Force update of existing files. diff --git a/share/nitdoc/css/Nitdoc.GitHub.css b/share/nitdoc/css/Nitdoc.GitHub.css deleted file mode 100644 index a2d675f..0000000 --- a/share/nitdoc/css/Nitdoc.GitHub.css +++ /dev/null @@ -1,231 +0,0 @@ -/* This file is part of NIT ( http://www.nitlanguage.org ). - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - Documentation generator for the nit language. - Generate API documentation in HTML format from nit source code. -*/ - -/* - * Nitdoc Github Login Box - */ - -#nitdoc-github-li.current { - color: #999; -} - -#nitdoc-github-li .glyphicon { - cursor: pointer; -} - -#nitdoc-github-loginbox { - cursor: default; - position: absolute; - width : 220px; - margin-top: 2px; - margin-left: -10px; - display: block; - padding: 10px; - text-align: left; - white-space: normal; - background-color: #ffffff; - border: 1px solid #ccc; - border: 1px solid rgba(0, 0, 0, 0.2); - -webkit-border-radius: 2px; - -moz-border-radius: 2px; - border-radius: 2px; - -webkit-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); - -moz-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); - box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); - -webkit-background-clip: padding-box; - -moz-background-clip: padding; - background-clip: padding-box; -} - -#nitdoc-github-loginbox .nitdoc-github-loginbox-arrow { - position: absolute; - display: block; - width: 0; - height: 0; - border-color: transparent; - border-style: solid; - border-width: 7px; - top: -7px; - margin-left: 2px; - border-bottom-color: #999; - border-bottom-color: rgba(0, 0, 0, 0.25); - border-top-width: 0; -} - -#nitdoc-github-loginbox .nitdoc-github-loginbox-arrow:after { - position: absolute; - display: block; - width: 0; - height: 0; - border-color: transparent; - border-style: solid; - border-width: 10px; - content: ""; - top: 1px; - margin-left: -10px; - border-bottom-color: #ffffff; - border-top-width: 0; -} - -#nitdoc-github-loginbox h3 { - text-align:center; -} - -#nitdoc-github-loginbox h4 { - display: block; - width: 100%; - color: #6C6C6C; - font-style: normal; - text-align: center; - margin-bottom: 20px; -} - - -#nitdoc-github-loginbox a.nitdoc-github-loginbox-githublink { - display: block; - margin: 10px; - color: #0D8921; -} - -/* Comment editing */ - -.nitdoc-github-commentbox { - margin: 1em 5px; - border: 1px solid #eee; - padding: 1em; - background: #fff; - -moz-box-shadow: 0 0 5px rgba(0, 0, 0, 0.2); - -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, 0.2); - box-shadow: 0 0 5px rgba(0, 0, 0, 0.2); -} - -.nitdoc-github-commentbox h3 { - margin: 0; -} - -.nitdoc-github-commentbox-buttons { - text-align: right; -} - -.nitdoc-github-commentbox dl { - margin-bottom: 0; -} - -.nitdoc-github-commentbox dt { - margin-bottom: 0.5em; -} - -.nitdoc-github-commentbox dd { - margin: 0 0 1em 0; -} - -.nitdoc-github-commentbox textarea { - display: block; - font-family: monospace; - font-size: 1em; - width: 100%; - padding: 4px; - padding-left: 11px; - overflow-y: hidden; - border: 1px solid #CCC; -} - -.nitdoc-github-preview { - margin: 0 15px; - cursor: pointer; -} - -.nitdoc-github-button.nitdoc-github-cancel { - background-color: #b33630; - background-image: -webkit-gradient(linear, left top, left bottom, from(#E97A74), to(#9f312c)); /* Saf4+, Chrome */ - background-image: -webkit-linear-gradient(top, #E97A74, #9f312c); /* Chrome 10+, Saf5.1+ */ - background-image: -moz-linear-gradient(top, #E97A74, #9f312c); /* FF3.6 */ - background-image: -ms-linear-gradient(top, #E97A74, #9f312c); /* IE10 */ - background-image: -o-linear-gradient(top, #E97A74, #9f312c); /* Opera 11.10+ */ - background-image: linear-gradient(top, #E97A74, #9f312c); - filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#E97A74', EndColorStr='#9f312c'); /* IE6–IE9 */ - border: 1px solid #9f312c; -} - -div.comment.locked { - color: gray; -} -p.locked { - color: black; -} - -a.nitdoc-github-cancel { - color: #b33630; - cursor: pointer; -} - -a.nitdoc-github-update { - color: orange; - cursor: pointer; -} - -.nitdoc-dialog h4 { - font-weight: bold; -} - -/* hljs */ - -.hljs.nitcode { - padding-left: 10px; -} - -.hljs-comment, .hljs-comment-block { - color: #777; -} - -.hljs-keyword { - color: #000; - font-weight: bold; -} - -.hljs-title { - font-weight: bold; -} - -.hljs-module { - color: #3762E4; -} - -.hljs-class .hljs-title { - color: #3762E4; -} - -.hljs-type { - color: #3762E4; -} - -.hljs-string { - color: #8F1546; -} - -.hljs-subst { - color: #9E6BEB; -} - -.hljs-fun .hljs-title { - color: #3762E4; -} - -.hljs-char, .hljs-number { - color: #009999; -} diff --git a/share/nitdoc/css/Nitdoc.ModalBox.css b/share/nitdoc/css/Nitdoc.ModalBox.css deleted file mode 100644 index bf9f9aa..0000000 --- a/share/nitdoc/css/Nitdoc.ModalBox.css +++ /dev/null @@ -1,110 +0,0 @@ -/* This file is part of NIT ( http://www.nitlanguage.org ). - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - Documentation generator for the nit language. - Generate API documentation in HTML format from nit source code. -*/ - -/* - * Nitdoc ModalBox style - */ - -.nitdoc-dialog-fade { - background: #000; - position: fixed; left: 0; top: 0; - width: 100%; height: 100%; - opacity: .80; - filter: alpha(opacity=80); - z-index: 9999; -} - -.nitdoc-dialog { - background: #fff; - border: 1px solid #ddd; - float: left; - position: fixed; - z-index: 99999; - -webkit-box-shadow: 0px 0px 20px #000; - -moz-box-shadow: 0px 0px 20px #000; - box-shadow: 0px 0px 20px #000; - -webkit-border-radius: 2px; - -moz-border-radius: 2px; - border-radius: 2px; - text-align: left; - min-width: 300px; -} - -.nitdoc-dialog-header { - padding: 10px 10px 10px 20px; - background: #f1f1f1; - border-bottom: 1px solid #ddd; -} - -.nitdoc-dialog-error .nitdoc-dialog-header { - background: #C92020; -} -.nitdoc-dialog-error .nitdoc-dialog-header h3 { - color: white; -} - -.nitdoc-dialog h3 { - display: inline; - margin: 0; -} - -.nitdoc-dialog-content { - max-height: 450px; - overflow-y: scroll; - padding: 10px; -} - -.nitdoc-dialog-buttons { - text-align: right; - padding: 5px; - border-top: 1px solid #ddd; -} - -.nitdoc-dialog textarea { - min-width: 300px; - width: 100%; -} - -.nitdoc-dialog button { - cursor: pointer; - border-radius: 2px; - -moz-border-radius: 2px; - -webkit-border-radius: 2px; - font-size: 14px; - padding: 5px 7px 5px 7px; - text-align: center; - background: #eee; - color: #333; - border: 1px solid #ddd; - font-weight: bold; -} - -.nitdoc-dialog button:hover { - background: #0D8921; - color: #fff; - border: 1px solid #1d7900; -} - -.nitdoc-dialog-close { - float: right; - padding: 5px; - margin: 0px; - line-height: 10px; - text-transform: lowercase; -} - diff --git a/share/nitdoc/css/Nitdoc.QuickSearch.css b/share/nitdoc/css/Nitdoc.QuickSearch.css deleted file mode 100644 index 81bba5d..0000000 --- a/share/nitdoc/css/Nitdoc.QuickSearch.css +++ /dev/null @@ -1,87 +0,0 @@ -/* This file is part of NIT ( http://www.nitlanguage.org ). - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - Documentation generator for the nit language. - Generate API documentation in HTML format from nit source code. -*/ - -/* - * Nitdoc Quick Search JS module - */ - -#nitdoc-qs-field { - width: 300px; - margin-top: 3px; -} - -#nitdoc-qs-table { - background-color: #FFFFFF; - border: 1px solid #E0E0E0; - border-spacing: 0px; - z-index: 1000; - -webkit-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); - -moz-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); - box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); -} - -#nitdoc-qs-table .nitdoc-qs-active { - cursor: pointer; - background: #EEE; -} - -#nitdoc-qs-table td, th { - white-space: nowrap; - overflow: hidden; - line-height: 22px; - padding: 2px; -} - -#nitdoc-qs-table td.nitdoc-qs-sub { - color: #6C6C6C; - padding-left: 12px; -} - -#nitdoc-qs-table td.nitdoc-qs-info { - color: #0D8921; - font-size: smaller; - text-align: right; -} - -#nitdoc-qs-table tr.nitdoc-qs-noresult td { - color: #6C6C6C; - font-size: small; - line-height: 15px; -} - -#nitdoc-qs-table tr.nitdoc-qs-overflow td { - text-align: center; - font-size: x-small; - line-height: 10px; - color: #FFF; - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} - -#nitdoc-qs-table tr.nitdoc-qs-overflow-active td { - color: #0D8921; - cursor: pointer; -} - -#nitdoc-qs-table tr.nitdoc-qs-overflow-active td:hover { - background-color: #E0E0E0; -} diff --git a/share/nitdoc/css/Nitdoc.UI.css b/share/nitdoc/css/Nitdoc.UI.css deleted file mode 100644 index 17b248d..0000000 --- a/share/nitdoc/css/Nitdoc.UI.css +++ /dev/null @@ -1,75 +0,0 @@ -/* This file is part of NIT ( http://www.nitlanguage.org ). - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - Documentation generator for the nit language. - Generate API documentation in HTML format from nit source code. -*/ - -/* - * Nitdoc UI JS module - */ - - -/* Folding */ - -a.nitdoc-ui-fold { - margin: 0 5px; - color: #999; - font-family: monospace; - font-weight: bold; - font-size: 120%; -} - -/* Search page field */ - -.nitdoc-ui-searchpage-field { - width: 750px; -} - -/* Side bar boxes text filtering */ - -.nitdoc-ui-filter { - text-align: center; - padding: 5px; -} - -.nitdoc-ui-filter-field { - width: 150px; - margin-right: 5px; -} - -.nitdoc-ui-filter-field-notused { - color: #999; - font-style: italic; -} - -/* Side bar boxes type filtering */ - -a.nitdoc-ui-filter-link { - color: #0D8921; - cursor: pointer; - font-family: monospace; - margin-right: 5px; - font-weight: bold; -} - -a.nitdoc-ui-filter-link:hover { - text-decoration: underline; -} - -a.nitdoc-ui-filter-hidden { - color: #999; - font-weight: normal; -} - diff --git a/share/nitdoc/css/nitdoc.bootstrap.css b/share/nitdoc/css/nitdoc.bootstrap.css index 0351b6f..fd80998 100644 --- a/share/nitdoc/css/nitdoc.bootstrap.css +++ b/share/nitdoc/css/nitdoc.bootstrap.css @@ -1,13 +1,3 @@ -/*! - * Bootstrap v3.1.1 - * - * Copyright 2014 Twitter, Inc - * Licensed under the Apache License v2.0 - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Designed and built with all the love in the world by @mdo and @fat. - * BootSwatchr built and provided by @DrewStrickland - */ /*! normalize.css v3.0.0 | MIT License | git.io/normalize */ html { font-family: sans-serif; @@ -275,11 +265,11 @@ html { -webkit-tap-highlight-color: rgba(0, 0, 0, 0); } body { - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-family: sans-serif; font-size: 14px; line-height: 1.428571429; color: #333333; - background-color: #ffffff; + background-color: #f2f2f2; } input, button, @@ -290,12 +280,12 @@ textarea { line-height: inherit; } a { - color: #222222; + color: #0d8921; text-decoration: none; } a:hover, a:focus { - color: #0d8921; + color: #064310; text-decoration: underline; } a:focus { @@ -319,14 +309,14 @@ img { height: auto; } .img-rounded { - border-radius: 4px; + border-radius: 0px; } .img-thumbnail { padding: 4px; line-height: 1.428571429; - background-color: #ffffff; + background-color: #f2f2f2; border: 1px solid #dddddd; - border-radius: 3px; + border-radius: 0px; -webkit-transition: all 0.2s ease-in-out; transition: all 0.2s ease-in-out; display: inline-block; @@ -340,7 +330,7 @@ hr { margin-top: 20px; margin-bottom: 20px; border: 0; - border-top: 1px solid #eeeeee; + border-top: 1px solid #ddd; } .sr-only { position: absolute; @@ -364,7 +354,7 @@ h6, .h4, .h5, .h6 { - font-family: inherit; + font-family: sans-serif; font-weight: 500; line-height: 1.1; color: inherit; @@ -453,11 +443,11 @@ h2, } h3, .h3 { - font-size: 24px; + font-size: 23px; } h4, .h4 { - font-size: 18px; + font-size: 17px; } h5, .h5 { @@ -465,7 +455,7 @@ h5, } h6, .h6 { - font-size: 12px; + font-size: 11px; } p { margin: 0 0 10px; @@ -516,10 +506,10 @@ a.text-success:hover { color: #449d44; } .text-info { - color: #6c6c6c; + color: #5bc0de; } a.text-info:hover { - color: #525252; + color: #31b0d5; } .text-warning { color: #f0ad4e; @@ -541,28 +531,28 @@ a.bg-primary:hover { background-color: #095a16; } .bg-success { - background-color: #eaf6ea; + background-color: #dff0d8; } a.bg-success:hover { - background-color: #c7e6c7; + background-color: #c1e2b3; } .bg-info { - background-color: #ececec; + background-color: #d9edf7; } a.bg-info:hover { - background-color: #d2d2d2; + background-color: #afd9ee; } .bg-warning { - background-color: #fef9f3; + background-color: #fcf8e3; } a.bg-warning:hover { - background-color: #fae3c4; + background-color: #f7ecb5; } .bg-danger { - background-color: #f9e2e2; + background-color: #f2dede; } a.bg-danger:hover { - background-color: #f0b9b8; + background-color: #e4b9b9; } .page-header { padding-bottom: 9px; @@ -587,13 +577,15 @@ ol ol { .list-inline { padding-left: 0; list-style: none; - margin-left: -5px; } .list-inline > li { display: inline-block; padding-left: 5px; padding-right: 5px; } +.list-inline > li:first-child { + padding-left: 0; +} dl { margin-top: 0; margin-bottom: 20px; @@ -692,7 +684,7 @@ code, kbd, pre, samp { - font-family: Menlo, Monaco, Consolas, "Courier New", monospace; + font-family: monospace; } code { padding: 2px 4px; @@ -700,14 +692,14 @@ code { color: #c7254e; background-color: #f9f2f4; white-space: nowrap; - border-radius: 3px; + border-radius: 0px; } kbd { padding: 2px 4px; font-size: 90%; color: #ffffff; background-color: #333333; - border-radius: 2px; + border-radius: 0px; box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25); } pre { @@ -721,7 +713,7 @@ pre { color: #333333; background-color: #f5f5f5; border: 1px solid #cccccc; - border-radius: 3px; + border-radius: 0px; } pre code { padding: 0; @@ -1440,7 +1432,7 @@ th { border-top: 2px solid #dddddd; } .table .table { - background-color: #ffffff; + background-color: #f2f2f2; } .table-condensed > thead > tr > th, .table-condensed > tbody > tr > th, @@ -1471,7 +1463,7 @@ th { } .table-hover > tbody > tr:hover > td, .table-hover > tbody > tr:hover > th { - background-color: #f5f5f5; + background-color: #dbdbdb; } table col[class*="col-"] { position: static; @@ -1496,13 +1488,13 @@ table th[class*="col-"] { .table > thead > tr.active > th, .table > tbody > tr.active > th, .table > tfoot > tr.active > th { - background-color: #f5f5f5; + background-color: #dbdbdb; } .table-hover > tbody > tr > td.active:hover, .table-hover > tbody > tr > th.active:hover, .table-hover > tbody > tr.active:hover > td, .table-hover > tbody > tr.active:hover > th { - background-color: #e8e8e8; + background-color: #cecece; } .table > thead > tr > td.success, .table > tbody > tr > td.success, @@ -1516,13 +1508,13 @@ table th[class*="col-"] { .table > thead > tr.success > th, .table > tbody > tr.success > th, .table > tfoot > tr.success > th { - background-color: #eaf6ea; + background-color: #dff0d8; } .table-hover > tbody > tr > td.success:hover, .table-hover > tbody > tr > th.success:hover, .table-hover > tbody > tr.success:hover > td, .table-hover > tbody > tr.success:hover > th { - background-color: #d8eed8; + background-color: #d0e9c6; } .table > thead > tr > td.info, .table > tbody > tr > td.info, @@ -1536,13 +1528,13 @@ table th[class*="col-"] { .table > thead > tr.info > th, .table > tbody > tr.info > th, .table > tfoot > tr.info > th { - background-color: #ececec; + background-color: #d9edf7; } .table-hover > tbody > tr > td.info:hover, .table-hover > tbody > tr > th.info:hover, .table-hover > tbody > tr.info:hover > td, .table-hover > tbody > tr.info:hover > th { - background-color: #dfdfdf; + background-color: #c4e3f3; } .table > thead > tr > td.warning, .table > tbody > tr > td.warning, @@ -1556,13 +1548,13 @@ table th[class*="col-"] { .table > thead > tr.warning > th, .table > tbody > tr.warning > th, .table > tfoot > tr.warning > th { - background-color: #fef9f3; + background-color: #fcf8e3; } .table-hover > tbody > tr > td.warning:hover, .table-hover > tbody > tr > th.warning:hover, .table-hover > tbody > tr.warning:hover > td, .table-hover > tbody > tr.warning:hover > th { - background-color: #fceedb; + background-color: #faf2cc; } .table > thead > tr > td.danger, .table > tbody > tr > td.danger, @@ -1576,13 +1568,13 @@ table th[class*="col-"] { .table > thead > tr.danger > th, .table > tbody > tr.danger > th, .table > tfoot > tr.danger > th { - background-color: #f9e2e2; + background-color: #f2dede; } .table-hover > tbody > tr > td.danger:hover, .table-hover > tbody > tr > th.danger:hover, .table-hover > tbody > tr.danger:hover > td, .table-hover > tbody > tr.danger:hover > th { - background-color: #f4cecd; + background-color: #ebcccc; } @media (max-width: 767px) { .table-responsive { @@ -1663,6 +1655,7 @@ input[type="checkbox"] { margin: 4px 0 0; margin-top: 1px \9; /* IE8-9 */ + line-height: normal; } input[type="file"] { @@ -1685,7 +1678,7 @@ input[type="checkbox"]:focus { } output { display: block; - padding-top: 3px; + padding-top: 7px; font-size: 14px; line-height: 1.428571429; color: #555555; @@ -1693,25 +1686,25 @@ output { .form-control { display: block; width: 100%; - height: 26px; - padding: 2px 5px; + height: 34px; + padding: 6px 12px; font-size: 14px; line-height: 1.428571429; color: #555555; background-color: #ffffff; background-image: none; border: 1px solid #cccccc; - border-radius: 3px; + border-radius: 0px; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; } .form-control:focus { - border-color: #6c6c6c; + border-color: #66afe9; outline: 0; - -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(108, 108, 108, 0.6); - box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(108, 108, 108, 0.6); + -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6); + box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6); } .form-control::-moz-placeholder { color: #999999; @@ -1737,7 +1730,7 @@ input[type="search"] { -webkit-appearance: none; } input[type="date"] { - line-height: 26px; + line-height: 34px; } .form-group { margin-bottom: 15px; @@ -1796,30 +1789,30 @@ fieldset[disabled] .checkbox-inline { cursor: not-allowed; } .input-sm { - height: 22px; - padding: 1px 5px; + height: 30px; + padding: 5px 10px; font-size: 12px; line-height: 1.5; - border-radius: 2px; + border-radius: 0px; } select.input-sm { - height: 22px; - line-height: 22px; + height: 30px; + line-height: 30px; } textarea.input-sm, select[multiple].input-sm { height: auto; } .input-lg { - height: 36px; - padding: 5px 10px; + height: 45px; + padding: 10px 16px; font-size: 18px; line-height: 1.33; - border-radius: 4px; + border-radius: 0px; } select.input-lg { - height: 36px; - line-height: 36px; + height: 45px; + line-height: 45px; } textarea.input-lg, select[multiple].input-lg { @@ -1829,16 +1822,16 @@ select[multiple].input-lg { position: relative; } .has-feedback .form-control { - padding-right: 32.5px; + padding-right: 42.5px; } .has-feedback .form-control-feedback { position: absolute; top: 25px; right: 0; display: block; - width: 26px; - height: 26px; - line-height: 26px; + width: 34px; + height: 34px; + line-height: 34px; text-align: center; } .has-success .help-block, @@ -1862,7 +1855,7 @@ select[multiple].input-lg { .has-success .input-group-addon { color: #5cb85c; border-color: #5cb85c; - background-color: #eaf6ea; + background-color: #dff0d8; } .has-success .form-control-feedback { color: #5cb85c; @@ -1888,7 +1881,7 @@ select[multiple].input-lg { .has-warning .input-group-addon { color: #f0ad4e; border-color: #f0ad4e; - background-color: #fef9f3; + background-color: #fcf8e3; } .has-warning .form-control-feedback { color: #f0ad4e; @@ -1914,7 +1907,7 @@ select[multiple].input-lg { .has-error .input-group-addon { color: #d9534f; border-color: #d9534f; - background-color: #f9e2e2; + background-color: #f2dede; } .has-error .form-control-feedback { color: #d9534f; @@ -1970,18 +1963,18 @@ select[multiple].input-lg { .form-horizontal .checkbox-inline { margin-top: 0; margin-bottom: 0; - padding-top: 3px; + padding-top: 7px; } .form-horizontal .radio, .form-horizontal .checkbox { - min-height: 23px; + min-height: 27px; } .form-horizontal .form-group { margin-left: -15px; margin-right: -15px; } .form-horizontal .form-control-static { - padding-top: 3px; + padding-top: 7px; } @media (min-width: 768px) { .form-horizontal .control-label { @@ -2002,18 +1995,17 @@ select[multiple].input-lg { background-image: none; border: 1px solid transparent; white-space: nowrap; - padding: 2px 5px; + padding: 6px 12px; font-size: 14px; line-height: 1.428571429; - border-radius: 3px; + border-radius: 0px; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; + -o-user-select: none; user-select: none; } -.btn:focus, -.btn:active:focus, -.btn.active:focus { +.btn:focus { outline: thin dotted; outline: 5px auto -webkit-focus-ring-color; outline-offset: -2px; @@ -2165,8 +2157,8 @@ fieldset[disabled] .btn-success.active { } .btn-info { color: #ffffff; - background-color: #6c6c6c; - border-color: #5f5f5f; + background-color: #5bc0de; + border-color: #46b8da; } .btn-info:hover, .btn-info:focus, @@ -2174,8 +2166,8 @@ fieldset[disabled] .btn-success.active { .btn-info.active, .open .dropdown-toggle.btn-info { color: #ffffff; - background-color: #585858; - border-color: #414141; + background-color: #39b3d7; + border-color: #269abc; } .btn-info:active, .btn-info.active, @@ -2197,11 +2189,11 @@ fieldset[disabled] .btn-info:active, .btn-info.disabled.active, .btn-info[disabled].active, fieldset[disabled] .btn-info.active { - background-color: #6c6c6c; - border-color: #5f5f5f; + background-color: #5bc0de; + border-color: #46b8da; } .btn-info .badge { - color: #6c6c6c; + color: #5bc0de; background-color: #ffffff; } .btn-warning { @@ -2287,7 +2279,7 @@ fieldset[disabled] .btn-danger.active { background-color: #ffffff; } .btn-link { - color: #222222; + color: #0d8921; font-weight: normal; cursor: pointer; border-radius: 0; @@ -2308,7 +2300,7 @@ fieldset[disabled] .btn-link { } .btn-link:hover, .btn-link:focus { - color: #0d8921; + color: #064310; text-decoration: underline; background-color: transparent; } @@ -2321,24 +2313,24 @@ fieldset[disabled] .btn-link:focus { } .btn-lg, .btn-group-lg > .btn { - padding: 5px 10px; + padding: 10px 16px; font-size: 18px; line-height: 1.33; - border-radius: 4px; + border-radius: 0px; } .btn-sm, .btn-group-sm > .btn { - padding: 1px 5px; + padding: 5px 10px; font-size: 12px; line-height: 1.5; - border-radius: 2px; + border-radius: 0px; } .btn-xs, .btn-group-xs > .btn { - padding: 0px 3px; + padding: 1px 5px; font-size: 12px; line-height: 1.5; - border-radius: 2px; + border-radius: 0px; } .btn-block { display: block; @@ -2377,8 +2369,8 @@ input[type="button"].btn-block { } @font-face { font-family: 'Glyphicons Halflings'; - src: url('../fonts/glyphicons-halflings-regular.eot'); - src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg'); + src: url('https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/fonts/glyphicons-halflings-regular.eot'); + src: url('https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/fonts/glyphicons-halflings-regular.woff') format('woff'), url('https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg'); } .glyphicon { position: relative; @@ -3022,7 +3014,7 @@ input[type="button"].btn-block { background-color: #ffffff; border: 1px solid #cccccc; border: 1px solid rgba(0, 0, 0, 0.15); - border-radius: 3px; + border-radius: 0px; -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); background-clip: padding-box; @@ -3049,8 +3041,8 @@ input[type="button"].btn-block { .dropdown-menu > li > a:hover, .dropdown-menu > li > a:focus { text-decoration: none; - color: #262626; - background-color: #f5f5f5; + color: #ffffff; + background-color: #0d8921; } .dropdown-menu > .active > a, .dropdown-menu > .active > a:hover, @@ -3253,12 +3245,12 @@ input[type="button"].btn-block { border-radius: 0; } .btn-group-vertical > .btn:first-child:not(:last-child) { - border-top-right-radius: 3px; + border-top-right-radius: 0px; border-bottom-right-radius: 0; border-bottom-left-radius: 0; } .btn-group-vertical > .btn:last-child:not(:first-child) { - border-bottom-left-radius: 3px; + border-bottom-left-radius: 0px; border-top-right-radius: 0; border-top-left-radius: 0; } @@ -3304,8 +3296,6 @@ input[type="button"].btn-block { padding-right: 0; } .input-group .form-control { - position: relative; - z-index: 2; float: left; width: 100%; margin-bottom: 0; @@ -3313,17 +3303,17 @@ input[type="button"].btn-block { .input-group-lg > .form-control, .input-group-lg > .input-group-addon, .input-group-lg > .input-group-btn > .btn { - height: 36px; - padding: 5px 10px; + height: 45px; + padding: 10px 16px; font-size: 18px; line-height: 1.33; - border-radius: 4px; + border-radius: 0px; } select.input-group-lg > .form-control, select.input-group-lg > .input-group-addon, select.input-group-lg > .input-group-btn > .btn { - height: 36px; - line-height: 36px; + height: 45px; + line-height: 45px; } textarea.input-group-lg > .form-control, textarea.input-group-lg > .input-group-addon, @@ -3336,17 +3326,17 @@ select[multiple].input-group-lg > .input-group-btn > .btn { .input-group-sm > .form-control, .input-group-sm > .input-group-addon, .input-group-sm > .input-group-btn > .btn { - height: 22px; - padding: 1px 5px; + height: 30px; + padding: 5px 10px; font-size: 12px; line-height: 1.5; - border-radius: 2px; + border-radius: 0px; } select.input-group-sm > .form-control, select.input-group-sm > .input-group-addon, select.input-group-sm > .input-group-btn > .btn { - height: 22px; - line-height: 22px; + height: 30px; + line-height: 30px; } textarea.input-group-sm > .form-control, textarea.input-group-sm > .input-group-addon, @@ -3373,7 +3363,7 @@ select[multiple].input-group-sm > .input-group-btn > .btn { vertical-align: middle; } .input-group-addon { - padding: 2px 5px; + padding: 6px 12px; font-size: 14px; font-weight: normal; line-height: 1; @@ -3381,17 +3371,17 @@ select[multiple].input-group-sm > .input-group-btn > .btn { text-align: center; background-color: #eeeeee; border: 1px solid #cccccc; - border-radius: 3px; + border-radius: 0px; } .input-group-addon.input-sm { - padding: 1px 5px; + padding: 5px 10px; font-size: 12px; - border-radius: 2px; + border-radius: 0px; } .input-group-addon.input-lg { - padding: 5px 10px; + padding: 10px 16px; font-size: 18px; - border-radius: 4px; + border-radius: 0px; } .input-group-addon input[type="radio"], .input-group-addon input[type="checkbox"] { @@ -3459,12 +3449,12 @@ select[multiple].input-group-sm > .input-group-btn > .btn { .nav > li > a { position: relative; display: block; - padding: 5px 10px; + padding: 10px 15px; } .nav > li > a:hover, .nav > li > a:focus { text-decoration: none; - background-color: #eeeeee; + background-color: #dddddd; } .nav > li.disabled > a { color: #999999; @@ -3479,8 +3469,8 @@ select[multiple].input-group-sm > .input-group-btn > .btn { .nav .open > a, .nav .open > a:hover, .nav .open > a:focus { - background-color: #eeeeee; - border-color: #222222; + background-color: #dddddd; + border-color: #0d8921; } .nav .nav-divider { height: 1px; @@ -3502,7 +3492,7 @@ select[multiple].input-group-sm > .input-group-btn > .btn { margin-right: 2px; line-height: 1.428571429; border: 1px solid transparent; - border-radius: 3px 3px 0 0; + border-radius: 0px 0px 0 0; } .nav-tabs > li > a:hover { border-color: #eeeeee #eeeeee #dddddd; @@ -3511,7 +3501,7 @@ select[multiple].input-group-sm > .input-group-btn > .btn { .nav-tabs > li.active > a:hover, .nav-tabs > li.active > a:focus { color: #555555; - background-color: #ffffff; + background-color: #f2f2f2; border: 1px solid #dddddd; border-bottom-color: transparent; cursor: default; @@ -3542,7 +3532,7 @@ select[multiple].input-group-sm > .input-group-btn > .btn { } .nav-tabs.nav-justified > li > a { margin-right: 0; - border-radius: 3px; + border-radius: 0px; } .nav-tabs.nav-justified > .active > a, .nav-tabs.nav-justified > .active > a:hover, @@ -3552,19 +3542,19 @@ select[multiple].input-group-sm > .input-group-btn > .btn { @media (min-width: 768px) { .nav-tabs.nav-justified > li > a { border-bottom: 1px solid #dddddd; - border-radius: 3px 3px 0 0; + border-radius: 0px 0px 0 0; } .nav-tabs.nav-justified > .active > a, .nav-tabs.nav-justified > .active > a:hover, .nav-tabs.nav-justified > .active > a:focus { - border-bottom-color: #ffffff; + border-bottom-color: #f2f2f2; } } .nav-pills > li { float: left; } .nav-pills > li > a { - border-radius: 3px; + border-radius: 0px; } .nav-pills > li + li { margin-left: 2px; @@ -3610,7 +3600,7 @@ select[multiple].input-group-sm > .input-group-btn > .btn { } .nav-tabs-justified > li > a { margin-right: 0; - border-radius: 3px; + border-radius: 0px; } .nav-tabs-justified > .active > a, .nav-tabs-justified > .active > a:hover, @@ -3620,12 +3610,12 @@ select[multiple].input-group-sm > .input-group-btn > .btn { @media (min-width: 768px) { .nav-tabs-justified > li > a { border-bottom: 1px solid #dddddd; - border-radius: 3px 3px 0 0; + border-radius: 0px 0px 0 0; } .nav-tabs-justified > .active > a, .nav-tabs-justified > .active > a:hover, .nav-tabs-justified > .active > a:focus { - border-bottom-color: #ffffff; + border-bottom-color: #f2f2f2; } } .tab-content > .tab-pane { @@ -3641,13 +3631,13 @@ select[multiple].input-group-sm > .input-group-btn > .btn { } .navbar { position: relative; - min-height: 30px; + min-height: 50px; margin-bottom: 20px; border: 1px solid transparent; } @media (min-width: 768px) { .navbar { - border-radius: 3px; + border-radius: 0px; } } @media (min-width: 768px) { @@ -3738,10 +3728,10 @@ select[multiple].input-group-sm > .input-group-btn > .btn { } .navbar-brand { float: left; - padding: 5px 15px; + padding: 15px 15px; font-size: 18px; line-height: 20px; - height: 30px; + height: 50px; } .navbar-brand:hover, .navbar-brand:focus { @@ -3758,12 +3748,12 @@ select[multiple].input-group-sm > .input-group-btn > .btn { float: right; margin-right: 15px; padding: 9px 10px; - margin-top: -2px; - margin-bottom: -2px; + margin-top: 8px; + margin-bottom: 8px; background-color: transparent; background-image: none; border: 1px solid transparent; - border-radius: 3px; + border-radius: 0px; } .navbar-toggle:focus { outline: none; @@ -3783,7 +3773,7 @@ select[multiple].input-group-sm > .input-group-btn > .btn { } } .navbar-nav { - margin: 2.5px -15px; + margin: 7.5px -15px; } .navbar-nav > li > a { padding-top: 10px; @@ -3821,8 +3811,8 @@ select[multiple].input-group-sm > .input-group-btn > .btn { float: left; } .navbar-nav > li > a { - padding-top: 5px; - padding-bottom: 5px; + padding-top: 15px; + padding-bottom: 15px; } .navbar-nav.navbar-right:last-child { margin-right: -15px; @@ -3844,8 +3834,8 @@ select[multiple].input-group-sm > .input-group-btn > .btn { border-bottom: 1px solid transparent; -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); - margin-top: 2px; - margin-bottom: 2px; + margin-top: 8px; + margin-bottom: 8px; } @media (min-width: 768px) { .navbar-form .form-group { @@ -3912,20 +3902,20 @@ select[multiple].input-group-sm > .input-group-btn > .btn { border-bottom-left-radius: 0; } .navbar-btn { - margin-top: 2px; - margin-bottom: 2px; + margin-top: 8px; + margin-bottom: 8px; } .navbar-btn.btn-sm { - margin-top: 4px; - margin-bottom: 4px; + margin-top: 10px; + margin-bottom: 10px; } .navbar-btn.btn-xs { - margin-top: 4px; - margin-bottom: 4px; + margin-top: 14px; + margin-bottom: 14px; } .navbar-text { - margin-top: 5px; - margin-bottom: 5px; + margin-top: 15px; + margin-bottom: 15px; } @media (min-width: 768px) { .navbar-text { @@ -3938,33 +3928,33 @@ select[multiple].input-group-sm > .input-group-btn > .btn { } } .navbar-default { - background-color: #f1f1f1; - border-color: #e0e0e0; + background-color: #0d8921; + border-color: none; } .navbar-default .navbar-brand { - color: #333333; + color: #ffffff; } .navbar-default .navbar-brand:hover, .navbar-default .navbar-brand:focus { - color: #1a1a1a; + color: #e6e6e6; background-color: transparent; } .navbar-default .navbar-text { - color: #333333; + color: #ffffff; } .navbar-default .navbar-nav > li > a { - color: #333333; + color: #ffffff; } .navbar-default .navbar-nav > li > a:hover, .navbar-default .navbar-nav > li > a:focus { - color: #0d8921; + color: #dddddd; background-color: transparent; } .navbar-default .navbar-nav > .active > a, .navbar-default .navbar-nav > .active > a:hover, .navbar-default .navbar-nav > .active > a:focus { color: #ffffff; - background-color: #0d8921; + background-color: #0a6b1a; } .navbar-default .navbar-nav > .disabled > a, .navbar-default .navbar-nav > .disabled > a:hover, @@ -3980,32 +3970,32 @@ select[multiple].input-group-sm > .input-group-btn > .btn { background-color: #dddddd; } .navbar-default .navbar-toggle .icon-bar { - background-color: #888888; + background-color: #ffffff; } .navbar-default .navbar-collapse, .navbar-default .navbar-form { - border-color: #e0e0e0; + border-color: none; } .navbar-default .navbar-nav > .open > a, .navbar-default .navbar-nav > .open > a:hover, .navbar-default .navbar-nav > .open > a:focus { - background-color: #0d8921; + background-color: #0a6b1a; color: #ffffff; } @media (max-width: 767px) { .navbar-default .navbar-nav .open .dropdown-menu > li > a { - color: #333333; + color: #ffffff; } .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover, .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus { - color: #0d8921; + color: #dddddd; background-color: transparent; } .navbar-default .navbar-nav .open .dropdown-menu > .active > a, .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover, .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus { color: #ffffff; - background-color: #0d8921; + background-color: #0a6b1a; } .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a, .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover, @@ -4015,10 +4005,10 @@ select[multiple].input-group-sm > .input-group-btn > .btn { } } .navbar-default .navbar-link { - color: #333333; + color: #ffffff; } .navbar-default .navbar-link:hover { - color: #0d8921; + color: #dddddd; } .navbar-inverse { background-color: #222222; @@ -4114,13 +4104,13 @@ select[multiple].input-group-sm > .input-group-btn > .btn { margin-bottom: 20px; list-style: none; background-color: #f5f5f5; - border-radius: 3px; + border-radius: 0px; } .breadcrumb > li { display: inline-block; } .breadcrumb > li + li:before { - content: "/\00a0"; + content: "\00a0"; padding: 0 5px; color: #cccccc; } @@ -4131,7 +4121,7 @@ select[multiple].input-group-sm > .input-group-btn > .btn { display: inline-block; padding-left: 0; margin: 20px 0; - border-radius: 3px; + border-radius: 0px; } .pagination > li { display: inline; @@ -4140,10 +4130,10 @@ select[multiple].input-group-sm > .input-group-btn > .btn { .pagination > li > span { position: relative; float: left; - padding: 2px 5px; + padding: 6px 12px; line-height: 1.428571429; text-decoration: none; - color: #222222; + color: #0d8921; background-color: #ffffff; border: 1px solid #dddddd; margin-left: -1px; @@ -4151,19 +4141,19 @@ select[multiple].input-group-sm > .input-group-btn > .btn { .pagination > li:first-child > a, .pagination > li:first-child > span { margin-left: 0; - border-bottom-left-radius: 3px; - border-top-left-radius: 3px; + border-bottom-left-radius: 0px; + border-top-left-radius: 0px; } .pagination > li:last-child > a, .pagination > li:last-child > span { - border-bottom-right-radius: 3px; - border-top-right-radius: 3px; + border-bottom-right-radius: 0px; + border-top-right-radius: 0px; } .pagination > li > a:hover, .pagination > li > span:hover, .pagination > li > a:focus, .pagination > li > span:focus { - color: #0d8921; + color: #064310; background-color: #eeeeee; border-color: #dddddd; } @@ -4192,33 +4182,33 @@ select[multiple].input-group-sm > .input-group-btn > .btn { } .pagination-lg > li > a, .pagination-lg > li > span { - padding: 5px 10px; + padding: 10px 16px; font-size: 18px; } .pagination-lg > li:first-child > a, .pagination-lg > li:first-child > span { - border-bottom-left-radius: 4px; - border-top-left-radius: 4px; + border-bottom-left-radius: 0px; + border-top-left-radius: 0px; } .pagination-lg > li:last-child > a, .pagination-lg > li:last-child > span { - border-bottom-right-radius: 4px; - border-top-right-radius: 4px; + border-bottom-right-radius: 0px; + border-top-right-radius: 0px; } .pagination-sm > li > a, .pagination-sm > li > span { - padding: 1px 5px; + padding: 5px 10px; font-size: 12px; } .pagination-sm > li:first-child > a, .pagination-sm > li:first-child > span { - border-bottom-left-radius: 2px; - border-top-left-radius: 2px; + border-bottom-left-radius: 0px; + border-top-left-radius: 0px; } .pagination-sm > li:last-child > a, .pagination-sm > li:last-child > span { - border-bottom-right-radius: 2px; - border-top-right-radius: 2px; + border-bottom-right-radius: 0px; + border-top-right-radius: 0px; } .pager { padding-left: 0; @@ -4305,11 +4295,11 @@ select[multiple].input-group-sm > .input-group-btn > .btn { background-color: #449d44; } .label-info { - background-color: #6c6c6c; + background-color: #5bc0de; } .label-info[href]:hover, .label-info[href]:focus { - background-color: #525252; + background-color: #31b0d5; } .label-warning { background-color: #f0ad4e; @@ -4331,7 +4321,7 @@ select[multiple].input-group-sm > .input-group-btn > .btn { padding: 3px 7px; font-size: 12px; font-weight: bold; - color: #ffffff; + color: : #fff; line-height: 1; vertical-align: baseline; white-space: nowrap; @@ -4358,41 +4348,41 @@ a.badge:focus { } a.list-group-item.active > .badge, .nav-pills > .active > a > .badge { - color: #222222; + color: #0d8921; background-color: #ffffff; } .nav-pills > li > a > .badge { margin-left: 3px; } .jumbotron { - padding: 20px; - margin-bottom: 20px; + padding: 30px; + margin-bottom: 30px; color: inherit; - background-color: #eeeeee; + background-color: #ffffff; } .jumbotron h1, .jumbotron .h1 { color: inherit; } .jumbotron p { - margin-bottom: 10px; - font-size: 17px; + margin-bottom: 15px; + font-size: 21px; font-weight: 200; } .container .jumbotron { - border-radius: 4px; + border-radius: 0px; } .jumbotron .container { max-width: 100%; } @media screen and (min-width: 768px) { .jumbotron { - padding-top: 32px; - padding-bottom: 32px; + padding-top: 48px; + padding-bottom: 48px; } .container .jumbotron { - padding-left: 40px; - padding-right: 40px; + padding-left: 60px; + padding-right: 60px; } .jumbotron h1, .jumbotron .h1 { @@ -4404,9 +4394,9 @@ a.list-group-item.active > .badge, padding: 4px; margin-bottom: 20px; line-height: 1.428571429; - background-color: #ffffff; + background-color: #f2f2f2; border: 1px solid #dddddd; - border-radius: 3px; + border-radius: 0px; -webkit-transition: all 0.2s ease-in-out; transition: all 0.2s ease-in-out; } @@ -4418,7 +4408,7 @@ a.list-group-item.active > .badge, a.thumbnail:hover, a.thumbnail:focus, a.thumbnail.active { - border-color: #222222; + border-color: #0d8921; } .thumbnail .caption { padding: 9px; @@ -4428,7 +4418,7 @@ a.thumbnail.active { padding: 15px; margin-bottom: 20px; border: 1px solid transparent; - border-radius: 3px; + border-radius: 0px; } .alert h4 { margin-top: 0; @@ -4454,45 +4444,45 @@ a.thumbnail.active { color: inherit; } .alert-success { - background-color: #eaf6ea; - border-color: #bcdfb5; + background-color: #dff0d8; + border-color: #d6e9c6; color: #5cb85c; } .alert-success hr { - border-top-color: #acd7a3; + border-top-color: #c9e2b3; } .alert-success .alert-link { color: #449d44; } .alert-info { - background-color: #ececec; - border-color: #d2d2d2; - color: #6c6c6c; + background-color: #d9edf7; + border-color: #bce8f1; + color: #5bc0de; } .alert-info hr { - border-top-color: #c5c5c5; + border-top-color: #a6e1ec; } .alert-info .alert-link { - color: #525252; + color: #31b0d5; } .alert-warning { - background-color: #fef9f3; - border-color: #fadac4; + background-color: #fcf8e3; + border-color: #fbeed5; color: #f0ad4e; } .alert-warning hr { - border-top-color: #f8ccac; + border-top-color: #f8e5be; } .alert-warning .alert-link { color: #ec971f; } .alert-danger { - background-color: #f9e2e2; - border-color: #f0b8c0; + background-color: #f2dede; + border-color: #eed3d7; color: #d9534f; } .alert-danger hr { - border-top-color: #eba3ad; + border-top-color: #e6c1c7; } .alert-danger .alert-link { color: #c9302c; @@ -4518,7 +4508,7 @@ a.thumbnail.active { height: 20px; margin-bottom: 20px; background-color: #f5f5f5; - border-radius: 3px; + border-radius: 0px; -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); } @@ -4553,7 +4543,7 @@ a.thumbnail.active { background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); } .progress-bar-info { - background-color: #6c6c6c; + background-color: #5bc0de; } .progress-striped .progress-bar-info { background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); @@ -4614,13 +4604,13 @@ a.thumbnail.active { border: 1px solid #dddddd; } .list-group-item:first-child { - border-top-right-radius: 3px; - border-top-left-radius: 3px; + border-top-right-radius: 0px; + border-top-left-radius: 0px; } .list-group-item:last-child { margin-bottom: 0; - border-bottom-right-radius: 3px; - border-bottom-left-radius: 3px; + border-bottom-right-radius: 0px; + border-bottom-left-radius: 0px; } .list-group-item > .badge { float: right; @@ -4655,11 +4645,11 @@ a.list-group-item.active:focus .list-group-item-heading { a.list-group-item.active .list-group-item-text, a.list-group-item.active:hover .list-group-item-text, a.list-group-item.active:focus .list-group-item-text { - color: #71f185; + color: #cccccc; } .list-group-item-success { color: #5cb85c; - background-color: #eaf6ea; + background-color: #dff0d8; } a.list-group-item-success { color: #5cb85c; @@ -4670,7 +4660,7 @@ a.list-group-item-success .list-group-item-heading { a.list-group-item-success:hover, a.list-group-item-success:focus { color: #5cb85c; - background-color: #d8eed8; + background-color: #d0e9c6; } a.list-group-item-success.active, a.list-group-item-success.active:hover, @@ -4680,30 +4670,30 @@ a.list-group-item-success.active:focus { border-color: #5cb85c; } .list-group-item-info { - color: #6c6c6c; - background-color: #ececec; + color: #5bc0de; + background-color: #d9edf7; } a.list-group-item-info { - color: #6c6c6c; + color: #5bc0de; } a.list-group-item-info .list-group-item-heading { color: inherit; } a.list-group-item-info:hover, a.list-group-item-info:focus { - color: #6c6c6c; - background-color: #dfdfdf; + color: #5bc0de; + background-color: #c4e3f3; } a.list-group-item-info.active, a.list-group-item-info.active:hover, a.list-group-item-info.active:focus { color: #fff; - background-color: #6c6c6c; - border-color: #6c6c6c; + background-color: #5bc0de; + border-color: #5bc0de; } .list-group-item-warning { color: #f0ad4e; - background-color: #fef9f3; + background-color: #fcf8e3; } a.list-group-item-warning { color: #f0ad4e; @@ -4714,7 +4704,7 @@ a.list-group-item-warning .list-group-item-heading { a.list-group-item-warning:hover, a.list-group-item-warning:focus { color: #f0ad4e; - background-color: #fceedb; + background-color: #faf2cc; } a.list-group-item-warning.active, a.list-group-item-warning.active:hover, @@ -4725,7 +4715,7 @@ a.list-group-item-warning.active:focus { } .list-group-item-danger { color: #d9534f; - background-color: #f9e2e2; + background-color: #f2dede; } a.list-group-item-danger { color: #d9534f; @@ -4736,7 +4726,7 @@ a.list-group-item-danger .list-group-item-heading { a.list-group-item-danger:hover, a.list-group-item-danger:focus { color: #d9534f; - background-color: #f4cecd; + background-color: #ebcccc; } a.list-group-item-danger.active, a.list-group-item-danger.active:hover, @@ -4757,7 +4747,7 @@ a.list-group-item-danger.active:focus { margin-bottom: 20px; background-color: #ffffff; border: 1px solid transparent; - border-radius: 3px; + border-radius: 0px; -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); } @@ -4767,8 +4757,8 @@ a.list-group-item-danger.active:focus { .panel-heading { padding: 10px 15px; border-bottom: 1px solid transparent; - border-top-right-radius: 2px; - border-top-left-radius: 2px; + border-top-right-radius: -1px; + border-top-left-radius: -1px; } .panel-heading > .dropdown .dropdown-toggle { color: inherit; @@ -4786,8 +4776,8 @@ a.list-group-item-danger.active:focus { padding: 10px 15px; background-color: #f5f5f5; border-top: 1px solid #dddddd; - border-bottom-right-radius: 2px; - border-bottom-left-radius: 2px; + border-bottom-right-radius: -1px; + border-bottom-left-radius: -1px; } .panel > .list-group { margin-bottom: 0; @@ -4796,15 +4786,19 @@ a.list-group-item-danger.active:focus { border-width: 1px 0; border-radius: 0; } -.panel > .list-group:first-child .list-group-item:first-child { +.panel > .list-group .list-group-item:first-child { border-top: 0; - border-top-right-radius: 2px; - border-top-left-radius: 2px; } -.panel > .list-group:last-child .list-group-item:last-child { +.panel > .list-group .list-group-item:last-child { border-bottom: 0; - border-bottom-right-radius: 2px; - border-bottom-left-radius: 2px; +} +.panel > .list-group:first-child .list-group-item:first-child { + border-top-right-radius: -1px; + border-top-left-radius: -1px; +} +.panel > .list-group:last-child .list-group-item:last-child { + border-bottom-right-radius: -1px; + border-bottom-left-radius: -1px; } .panel-heading + .list-group .list-group-item:first-child { border-top-width: 0; @@ -4813,11 +4807,6 @@ a.list-group-item-danger.active:focus { .panel > .table-responsive > .table { margin-bottom: 0; } -.panel > .table:first-child, -.panel > .table-responsive:first-child > .table:first-child { - border-top-right-radius: 2px; - border-top-left-radius: 2px; -} .panel > .table:first-child > thead:first-child > tr:first-child td:first-child, .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child, .panel > .table:first-child > tbody:first-child > tr:first-child td:first-child, @@ -4826,7 +4815,7 @@ a.list-group-item-danger.active:focus { .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child, .panel > .table:first-child > tbody:first-child > tr:first-child th:first-child, .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child { - border-top-left-radius: 2px; + border-top-left-radius: -1px; } .panel > .table:first-child > thead:first-child > tr:first-child td:last-child, .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child, @@ -4836,12 +4825,7 @@ a.list-group-item-danger.active:focus { .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child, .panel > .table:first-child > tbody:first-child > tr:first-child th:last-child, .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child { - border-top-right-radius: 2px; -} -.panel > .table:last-child, -.panel > .table-responsive:last-child > .table:last-child { - border-bottom-right-radius: 2px; - border-bottom-left-radius: 2px; + border-top-right-radius: -1px; } .panel > .table:last-child > tbody:last-child > tr:last-child td:first-child, .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child, @@ -4851,7 +4835,7 @@ a.list-group-item-danger.active:focus { .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child, .panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child, .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child { - border-bottom-left-radius: 2px; + border-bottom-left-radius: -1px; } .panel > .table:last-child > tbody:last-child > tr:last-child td:last-child, .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child, @@ -4861,7 +4845,7 @@ a.list-group-item-danger.active:focus { .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child, .panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child, .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child { - border-bottom-right-radius: 2px; + border-bottom-right-radius: -1px; } .panel > .panel-body + .table, .panel > .panel-body + .table-responsive { @@ -4932,7 +4916,7 @@ a.list-group-item-danger.active:focus { } .panel-group .panel { margin-bottom: 0; - border-radius: 3px; + border-radius: 0px; overflow: hidden; } .panel-group .panel + .panel { @@ -4979,60 +4963,60 @@ a.list-group-item-danger.active:focus { border-bottom-color: #0d8921; } .panel-success { - border-color: #bcdfb5; + border-color: #d6e9c6; } .panel-success > .panel-heading { color: #5cb85c; - background-color: #eaf6ea; - border-color: #bcdfb5; + background-color: #dff0d8; + border-color: #d6e9c6; } .panel-success > .panel-heading + .panel-collapse .panel-body { - border-top-color: #bcdfb5; + border-top-color: #d6e9c6; } .panel-success > .panel-footer + .panel-collapse .panel-body { - border-bottom-color: #bcdfb5; + border-bottom-color: #d6e9c6; } .panel-info { - border-color: #d2d2d2; + border-color: #bce8f1; } .panel-info > .panel-heading { - color: #6c6c6c; - background-color: #ececec; - border-color: #d2d2d2; + color: #5bc0de; + background-color: #d9edf7; + border-color: #bce8f1; } .panel-info > .panel-heading + .panel-collapse .panel-body { - border-top-color: #d2d2d2; + border-top-color: #bce8f1; } .panel-info > .panel-footer + .panel-collapse .panel-body { - border-bottom-color: #d2d2d2; + border-bottom-color: #bce8f1; } .panel-warning { - border-color: #fadac4; + border-color: #fbeed5; } .panel-warning > .panel-heading { color: #f0ad4e; - background-color: #fef9f3; - border-color: #fadac4; + background-color: #fcf8e3; + border-color: #fbeed5; } .panel-warning > .panel-heading + .panel-collapse .panel-body { - border-top-color: #fadac4; + border-top-color: #fbeed5; } .panel-warning > .panel-footer + .panel-collapse .panel-body { - border-bottom-color: #fadac4; + border-bottom-color: #fbeed5; } .panel-danger { - border-color: #f0b8c0; + border-color: #eed3d7; } .panel-danger > .panel-heading { color: #d9534f; - background-color: #f9e2e2; - border-color: #f0b8c0; + background-color: #f2dede; + border-color: #eed3d7; } .panel-danger > .panel-heading + .panel-collapse .panel-body { - border-top-color: #f0b8c0; + border-top-color: #eed3d7; } .panel-danger > .panel-footer + .panel-collapse .panel-body { - border-bottom-color: #f0b8c0; + border-bottom-color: #eed3d7; } .well { min-height: 20px; @@ -5040,7 +5024,7 @@ a.list-group-item-danger.active:focus { margin-bottom: 20px; background-color: #f5f5f5; border: 1px solid #e3e3e3; - border-radius: 3px; + border-radius: 0px; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); } @@ -5050,11 +5034,11 @@ a.list-group-item-danger.active:focus { } .well-lg { padding: 24px; - border-radius: 4px; + border-radius: 0px; } .well-sm { padding: 9px; - border-radius: 2px; + border-radius: 0px; } .close { float: right; @@ -5121,7 +5105,7 @@ button.close { background-color: #ffffff; border: 1px solid #999999; border: 1px solid rgba(0, 0, 0, 0.2); - border-radius: 4px; + border-radius: 0px; -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); background-clip: padding-box; @@ -5231,7 +5215,7 @@ button.close { text-align: center; text-decoration: none; background-color: #000000; - border-radius: 3px; + border-radius: 0px; } .tooltip-arrow { position: absolute; @@ -5305,7 +5289,7 @@ button.close { background-clip: padding-box; border: 1px solid #cccccc; border: 1px solid rgba(0, 0, 0, 0.2); - border-radius: 4px; + border-radius: 0px; -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); white-space: normal; @@ -5570,8 +5554,8 @@ button.close { text-shadow: none; } @media screen and (min-width: 768px) { - .carousel-control .glyphicon-chevron-left, - .carousel-control .glyphicon-chevron-right, + .carousel-control .glyphicons-chevron-left, + .carousel-control .glyphicons-chevron-right, .carousel-control .icon-prev, .carousel-control .icon-next { width: 30px; diff --git a/share/nitdoc/css/nitdoc.cards.css b/share/nitdoc/css/nitdoc.cards.css new file mode 100644 index 0000000..fc3e5ef --- /dev/null +++ b/share/nitdoc/css/nitdoc.cards.css @@ -0,0 +1,68 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* cards */ + +.card.active { + border: 1px solid #1E9431; +} + +.card-heading { + margin-top: 0; + margin-bottom: 5px; +} + +.card { + display: table; + width: 100%; + background: #fff; + border: 1px solid #eee; + margin-top: 10px; + box-shadow: -1px -1px 3px rgba(0,0,0,.06), 1px 1px 3px rgba(0,0,0,.12); +} + +.card-body, .card-left, .card-right { + display: table-cell; + padding: 15px; +} + +.card-body { + padding: 15px 0; + width: 100% +} + +.card-body:first-child { + padding-left: 15px; +} + +.card-body:last-child { + padding-right: 15px; +} + +.card-list { + margin-top: 10px; +} + +.card-list > .card:first-child { + border-top: 1px solid #ddd; +} + +.card-list > .card { + margin-top: 0; + border-top: none; +} + +.card-title { + margin-top: 0; +} diff --git a/share/nitdoc/css/nitdoc.code.css b/share/nitdoc/css/nitdoc.code.css new file mode 100644 index 0000000..2a944aa --- /dev/null +++ b/share/nitdoc/css/nitdoc.code.css @@ -0,0 +1,47 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Code Highlighting */ + +.nitcode a { color: inherit; text-decoration: inherit; } /* hide links */ +.nitcode a:hover { text-decoration: underline; } /* underline links */ + +/* lexical raw tokens. independent of usage or semantic: */ +.nitcode .nc_c { color: gray; font-style: italic; } /* comment */ +.nitcode .nc_d { color: #3D8127; font-style: italic; } /* documentation comments */ +.nitcode .nc_k { font-weight: bold; } /* keyword */ +.nitcode .nc_o {} /* operator */ +.nitcode .nc_i {} /* standard identifier */ +.nitcode .nc_t { color: #445588; font-weight: bold; } /* type/class identifier */ +.nitcode .nc_a { color: #445588; font-style: italic; } /* old style attribute identifier */ +.nitcode .nc_l { color: #009999; } /* char and number literal */ +.nitcode .nc_s { color: #8F1546; } /* string literal */ + +/* syntactic token usage. added because of their position in the AST */ +.nitcode .nc_ast { color: blue; } /* assert label */ +.nitcode .nc_la { color: blue; } /* break/continue label */ +.nitcode .nc_m { color: #445588; } /* module name */ + +/* syntactic groups */ +.nitcode .nc_def { font-weight: bold; color: blue; } /* name used in a definition */ +.nitcode .nc_def.nc_a { color: blue; } /* name used in a attribute definition */ +.nitcode .nc_def.nc_t { color: blue; } /* name used in a class or vt definition */ +.nitcode .nc_ss { color: #9E6BEB; } /* superstrings */ +.nitcode .nc_cdef {} /* A whole class definition */ +.nitcode .nc_pdef {} /* A whole property definition */ + +/* semantic token usage */ +.nitcode .nc_v { font-style: italic; } /* local variable or parameter */ +.nitcode .nc_vt { font-style: italic; } /* virtual type or formal type */ +.nitcode .nc_error { border: 1px red solid;} /* not used */ diff --git a/share/nitdoc/css/nitdoc.css b/share/nitdoc/css/nitdoc.css index 01da471..81153c7 100644 --- a/share/nitdoc/css/nitdoc.css +++ b/share/nitdoc/css/nitdoc.css @@ -1,271 +1,116 @@ /* - * Global + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ -body { - text-align: justify; -} - -a:hover { - text-decoration: none; -} - -ul li .label { - padding: 1px 4px; - font-size: 70%; - vertical-align: middle; - border-radius: .25em; - margin: 3px; - font-family: monospace; -} - -code { - color: #333; - border: 1px solid #ddd; -} +/* Top menu */ -pre code { - border: none; +.navbar-fixed-top { + background-color: #1E9431; + box-shadow: 0 0 4px rgba(0,0,0,.14),0 4px 8px rgba(0,0,0,.28); } -.navbar-default .navbar-toggle { - margin-top: 2px; - padding: 5px 10px; +.navbar-brand > a { + color: #fff; } -h3 { - margin: 10px 0; +.container > .navbar-header, .container-fluid > .navbar-header, .container > .navbar-collapse, .container-fluid > .navbar-collapse { + margin-right: auto; + margin-left: auto; } -article { - padding: 10px 0px; +.navbar-default .navbar-collapse, .navbar-default .navbar-form { + border-color: transparent; } -article.nospace { - padding: 0; - margin: 0; +.navbar-toggle { + float: left; } -/* - * Sidebar - */ +/* Body */ -#sidebar .panel { - margin-top: 15px; - box-shadow: none; -} - -#sidebar .panel-heading { - padding: 3px 0 0 0; - font-size: 16px; -} - -#sidebar .panel-body { - padding: 0; -} - -#sidebar .panel-body ul>li>a { - padding: 0; -} - -#sidebar .panel-body ul>li { - padding: 0 0 0 15px; - font-size: 15px; - color: #333; +body { + background: #f2f2f2; + margin-top: 70px; + margin-bottom: 70px; } -#sidebar .panel-body ul ul>li, -#sidebar .panel-body ul ul>li a { - padding: 0 0 0 0; - font-size: 14px; +h1, h2, h3, h4, h5, h6 { color: #666; } -#sidebar .panel-body ul ul ul>li { - font-size: 13px; - color: #999; +.page-header { + margin-top: 0; + border: none; } -#sidebar .panel-heading a:hover, #sidebar .panel ul a:hover { - color: #0d8921; - background-color: transparent; -} - -#sidebar .summary .nav>li>a { - padding: 3px 0 0 10px; - font-size: 15px; - border-left: 2px solid transparent; - color: #333; -} +#sidebar { margin-top: 15px; } -#sidebar .summary .nav .nav>li>a { - padding-top: 2px; - padding-left: 15px; - font-size: 14px; - color: #666; +pre { + white-space: pre-wrap; } -#sidebar .summary .nav .nav .nav>li>a { - padding-left: 20px; - font-size: 13px; +.footer { color: #999; + text-align: center; + padding: 10px; + margin: 20px 0; } -#sidebar .summary .nav .nav .nav .nav>li>a { - font-size: 12px; - color: #CCC; -} - -#sidebar .summary .nav>.active>a, -#sidebar .summary .nav>.active>a:hover, -#sidebar .summary .nav>li>a:hover { - color: #0d8921; - background-color: transparent; -} - -#sidebar .summary .nav>.active>a, -#sidebar .summary .nav>.active>a:hover, -#sidebar .summary .nav .nav>.active>a, -#sidebar .summary .nav .nav>.active>a:hover, -#sidebar .summary .nav .nav .nav>.active>a, -#sidebar .summary .nav .nav .nav>.active>a:hover { - color: #0d8921; - border-left: 2px solid #0d8921; - margin-left: 0px; -} - -#sidebar .summary .nav>li>a:hover, -#sidebar .summary .nav .nav>li>a:hover, -#sidebar .summary .nav .nav .nav>li>a:hover { - color: #0d8921; - border-left: 1px solid #0d8921; - margin-left: 1px; - background-color: transparent; -} - -/* - * Content - */ - -#content { - position: fixed; - top: 30px; - bottom: 0; - left: 10px; - right: 15px; -} - -#content>.col { - height: 100%; - overflow-y: scroll; -} - -#content>.col::-webkit-scrollbar-thumb { - background: transparent; -} +/* ui */ -#content>.col:hover::-webkit-scrollbar-thumb { - background: #CCC; - -webkit-box-shadow: inset 1px 1px 0 rgba(0,0,0,0.10),inset 0 -1px 0 rgba(0,0,0,0.07); -} +.btn-bar { margin-top: -5px; float: right } +.btn-bar .btn { padding: 5px 10px; } -#content>.col::-webkit-scrollbar { - width: 7px; - height: 7px; -} +/* Doc */ -#content>.col::-webkit-scrollbar-thumb:hover { - background: #999; +.nitdoc > *:first-child { + margin-top: 0; } -#content>.col::-webkit-scrollbar-corner { - background: transparent; +.signature { + color: #777; + font-family: monospace; } -#content>.col::-webkit-scrollbar-button { - width: 0; - height: 0; - display: none; +.signature .name { + font-weight: bold; } -#content article:target { - padding-left: 10px; - margin-left: -10px; - border-left: 2px solid #0d8921; +.page-header .signature .name, .signature .signature .name { + font-weight: normal; } +/* Summary */ -.pull-right .dropdown-toggle { - padding: 0 5px; -} - -/* Hide the "..." link */ +.summary h1 { font-size: 14px; margin: 10px 0 5px 0; font-weight: bold; } +.summary h2 { font-size: 13px; margin: 9px 0 5px 5px; font-weight: bold; } +.summary h3 { font-size: 12px; margin: 8px 0 5px 10px; } +.summary h4 { font-size: 11px; margin: 7px 0 5px 15px; } +.summary h5 { font-size: 10px; margin: 6px 0 5px 20px; } +.summary h6 { font-size: 9px; margin: 5px 0 5px 25px; } -article .dropdown, article .dropdown { - visibility: hidden; -} -article:hover .dropdown, article:target .dropdown { - visibility: visible; -} +.summary a, .summary a:hover { color: #666; } /* - * Page parts + * Nit */ -.footer { - padding: 10px; - margin: 20px 0; -} - -.subtitle { - margin-bottom: 10px; -} - -.label:empty { - display:inline; -} - -.label.intro:before { - content: "I"; -} -.label.redef:before { - content: "R"; -} -.label.inherit:before { - content: "H"; -} - -.signature span.glyphicon { - margin: 0 10px 5px 0; - font-size: 55%; - vertical-align: middle; -} - -.signature a, .list-definition a, .info.signature a { - color: #0d8921; -} - -.info { - color: #888; -} - -.info a { - color: #666; -} - -.info a:hover { +.nitdoc h1, .nitdoc h2, .nitdoc h3, .nitdoc h4, .nitdoc h5, .nitdoc h6 { color: #333; } -.graph { - text-align: center; -} - .nitdoc .synopsys { - margin: 5px 0; - font-size: 16px; - font-weight: bold; - line-height: 1.4; + margin-top: 0; } .public { @@ -279,41 +124,3 @@ article:hover .dropdown, article:target .dropdown { .private { color: #a94442; } - -.list-definition .list-definition { - margin-left: 30px; -} - -/* - * Code Highlighting - */ - -.nitcode a { color: inherit; text-decoration: inherit; } /* hide links */ -.nitcode a:hover { text-decoration: underline; } /* underline links */ -.nitcode span[title]:hover { text-decoration: underline; } /* underline titles */ -/* lexical raw tokens. independent of usage or semantic: */ -.nitcode .nc_c { color: gray; font-style: italic; } /* comment */ -.nitcode .nc_d { color: #3D8127; font-style: italic; } /* documentation comments */ -.nitcode .nc_k { font-weight: bold; } /* keyword */ -.nitcode .nc_o {} /* operator */ -.nitcode .nc_i {} /* standard identifier */ -.nitcode .nc_t { color: #445588; font-weight: bold; } /* type/class identifier */ -.nitcode .nc_a { color: #445588; font-style: italic; } /* old style attribute identifier */ -.nitcode .nc_l { color: #009999; } /* char and number literal */ -.nitcode .nc_s { color: #8F1546; } /* string literal */ -/* syntactic token usage. added because of their position in the AST */ -.nitcode .nc_ast { color: blue; } /* assert label */ -.nitcode .nc_la { color: blue; } /* break/continue label */ -.nitcode .nc_m { color: #445588; } /* module name */ -/* syntactic groups */ -.nitcode .nc_def { font-weight: bold; color: blue; } /* name used in a definition */ -.nitcode .nc_def.nc_a { color: blue; } /* name used in a attribute definition */ -.nitcode .nc_def.nc_t { color: blue; } /* name used in a class or vt definition */ -.nitcode .nc_ss { color: #9E6BEB; } /* superstrings */ -.nitcode .nc_cdef {} /* A whole class definition */ -.nitcode .nc_pdef {} /* A whole property definition */ -/* semantic token usage */ -.nitcode .nc_v { font-style: italic; } /* local variable or parameter */ -.nitcode .nc_vt { font-style: italic; } /* virtual type or formal type */ -.nitcode .nc_error { border: 1px red solid;} /* not used */ - diff --git a/share/nitdoc/css/nitdoc.quicksearch.css b/share/nitdoc/css/nitdoc.quicksearch.css new file mode 100644 index 0000000..3e306c3 --- /dev/null +++ b/share/nitdoc/css/nitdoc.quicksearch.css @@ -0,0 +1,123 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Nitdoc Quick Search JS module */ + +.has-icon { + position: relative; +} + +.has-icon .form-control { + padding-left: 35px; +} + +.form-control-icon { + position: absolute; + top: 0; + left: 0; + z-index: 2; + display: block; + width: 34px; + height: 34px; + line-height: 34px; + text-align: center; + pointer-events: none; +} + +.navbar-fixed-top .form-control:hover, .navbar-fixed-top .form-control:focus { + background: rgba(255, 255, 255, 0.2); +} + +.navbar-fixed-top .form-control { + background: rgba(255, 255, 255, 0.1); + border: none; + color: #fff; + box-shadow: none; +} + +.navbar-fixed-top .form-control-icon { + color: #fff; +} + +.navbar-fixed-top .form-group { + margin-top: 8px; + margin-bottom: 0px; +} + +.navbar-fixed-top *::-webkit-input-placeholder { color: #fff; } +.navbar-fixed-top *:-moz-placeholder { color: #fff; } +.navbar-fixed-top *::-moz-placeholder { color: #fff; } +.navbar-fixed-top *:-ms-input-placeholder { color: #fff; } + +.search-input { + width: 100%; +} + +#nitdoc-qs-popup { + background-color: #FFFFFF; + border: 1px solid #E0E0E0; + z-index: 1000; + -webkit-box-shadow: 0 1px 5px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 1px 5px rgba(0, 0, 0, 0.2); + box-shadow: 0 1px 5px rgba(0, 0, 0, 0.2); +} + +.qs-card { + cursor: pointer; + padding: 5px; + border-bottom: 1px solid #F0F0F0; + overflow: hidden; +} + +.qs-card h1 { + color: #0D8921; + font-size: 1.2em; + margin-top: 5px; + margin-bottom: 0; +} + +.qs-info { + color: #6C6C6C; + font-size: smaller; +} + +.qs-noresult { + color: #6C6C6C; + font-size: small; +} + +.qs-overflow { + text-align: center; + font-size: x-small; + color: #6C6C6C; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.qs-overflow-active { + color: #0D8921; + cursor: pointer; +} + +.qs-overflow-active:hover { + background-color: #E0E0E0; +} + +.qs-active { + background: #EEE; +} diff --git a/share/nitdoc/js/lib/github-api.js b/share/nitdoc/js/lib/github-api.js deleted file mode 100644 index f03188a..0000000 --- a/share/nitdoc/js/lib/github-api.js +++ /dev/null @@ -1,295 +0,0 @@ -/* This file is part of NIT ( http://www.nitlanguage.org ). - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - Documentation generator for the nit language. - Generate API documentation in HTML format from nit source code. -*/ - -/* - * GitHub API wrapper for github plugin - */ -define([ - "jquery", - "utils" -], function($, Utils) { - return { - - // try to login the user to github API - login: function(user) { - var res = false; - $.ajax({ - beforeSend: function (xhr) { - xhr.setRequestHeader ("Authorization", user.auth); - }, - type: "GET", - url: "https://api.github.com/repos/" + user.login + "/" + user.repo, - async: false, - dataType: 'json', - success: function() { - res = true; - } - }); - user.infos = this.getUserInfos(user); - user.signedOff = this.getSignedOff(user) - return res; - }, - - // request for user github account infos - getUserInfos: function(user) { - var res = false; - $.ajax({ - beforeSend: function (xhr) { - xhr.setRequestHeader ("Authorization", user.auth); - }, - type: "GET", - url: "https://api.github.com/users/" + user.login, - async: false, - dataType: 'json', - success: function(response) { - res = response; - }, - error: function(response) { - res = response; - } - }); - return res; - }, - - // build signedoff user default signature - getSignedOff: function(user) { - return user.infos.name + " <" + user.infos.email + ">"; - }, - - // get the branches list from a repo - getBranches: function(user) { - var res = false; - $.ajax({ - beforeSend: function (xhr) { - xhr.setRequestHeader ("Authorization", user.auth); - }, - type: "GET", - url: "https://api.github.com/repos/" + user.login + "/" + user.repo + "/branches", - async: false, - dataType: 'json', - success: function(response) { - res = response; - }, - error: function(response) { - res = response; - } - }); - return res; - }, - - /* GitHub commits */ - - // get the latest commit on `branchName` - getCommit: function(user, sha) { - var res = false; - $.ajax({ - beforeSend: function (xhr) { - xhr.setRequestHeader ("Authorization", user.auth); - }, - type: "GET", - url: "https://api.github.com/repos/" + user.login + "/" + user.repo + "/git/commits/" + sha, - async: false, - dataType: 'json', - success: function(response) { - res = response; - }, - error: function(response) { - res = response; - } - }); - return res; - }, - - // get the base tree for a commit sha - getTree: function(user, sha) { - var res = false; - $.ajax({ - beforeSend: function (xhr) { - xhr.setRequestHeader ("Authorization", user.auth); - }, - type: "GET", - url: "https://api.github.com/repos/" + user.login + "/" + user.repo + "/git/trees/" + sha + "?recursive=1", - async: false, - dataType: 'json', - success: function(response) { - res = response; - }, - error: function(response) { - res = response; - } - }); - return res; - }, - - // create a new blob - createBlob: function(user, content) { - var res = false; - $.ajax({ - beforeSend: function (xhr) { - xhr.setRequestHeader ("Authorization", user.auth); - }, - type: "POST", - url: "https://api.github.com/repos/" + user.login + "/" + user.repo + "/git/blobs", - async: false, - dataType: 'json', - data: JSON.stringify({ - content: content.base64Encode(), - encoding: "base64" - }), - success: function(response) { - res = response; - }, - error: function(response) { - res = response; - } - }); - return res; - }, - - // create a new tree from a base tree - createTree: function(user, baseTree, path, blob) { - var res = false; - $.ajax({ - beforeSend: function (xhr) { - xhr.setRequestHeader ("Authorization", user.auth); - }, - type: "POST", - url: "https://api.github.com/repos/" + user.login + "/" + user.repo + "/git/trees", - data: JSON.stringify({ - base_tree: baseTree.sha, - tree: [{ - path: path, - mode: "100644", // file (blob) - type: "blob", - sha: blob.sha - }] - }), - async: false, - dataType: 'json', - success: function(response) { - res = response; - }, - error: function(response) { - res = response; - } - }); - return res; - }, - - // create a new commit - createCommit: function(user, message, parentCommit, tree) { - var res = false; - $.ajax({ - beforeSend: function (xhr) { - xhr.setRequestHeader ("Authorization", user.auth); - }, - type: "POST", - url: "https://api.github.com/repos/" + user.login + "/" + user.repo + "/git/commits", - data: JSON.stringify({ - message: message, - parents: parentCommit, - tree: tree.sha, - }), - async: false, - dataType: 'json', - success: function(response) { - res = response; - }, - error: function(response) { - res = response; - } - }); - return res; - }, - - // create a pull request - createPullRequest: function(user, title, body, origin, head) { - var res = false; - $.ajax({ - beforeSend: function (xhr) { - xhr.setRequestHeader ("Authorization", user.auth); - }, - type: "POST", - url: "https://api.github.com/repos/" + origin.user + "/" + origin.repo + "/pulls", - data: JSON.stringify({ - title: title, - body: body, - base: origin.branch, - head: user.login + ":" + head - }), - async: false, - dataType: 'json', - success: function(response) { - res = response; - }, - error: function(response) { - res = response; - } - }); - return res; - }, - - // update a pull request - updatePullRequest: function(user, title, body, state, request) { - var res = false; - $.ajax({ - beforeSend: function (xhr) { - xhr.setRequestHeader ("Authorization", user.auth); - }, - type: "PATCH", - url: request.url, - data: JSON.stringify({ - title: title, - body: body, - state: state - }), - async: false, - dataType: 'json', - success: function(response) { - res = response; - }, - error: function(response) { - res = response; - } - }); - return res; - }, - - /* Files */ - - getFile: function(user, path, branch) { - var res = false; - $.ajax({ - type: "GET", - url: "https://api.github.com/repos/" + user.login + "/" + user.repo + "/contents/" + path, - data: { - ref: branch - }, - async: false, - dataType: 'json', - success: function(response) { - res = response; - }, - error: function(response) { - res = response; - } - }); - return res; - } - } -}); diff --git a/share/nitdoc/js/lib/highlight.js b/share/nitdoc/js/lib/highlight.js deleted file mode 100644 index bd277ee..0000000 --- a/share/nitdoc/js/lib/highlight.js +++ /dev/null @@ -1,715 +0,0 @@ -/* Copyright (c) 2006, Ivan Sagalaev - All rights reserved. - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of highlight.js nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -var hljs = new function() { - - /* Utility functions */ - - function escape(value) { - return value.replace(/&/gm, '&').replace(//gm, '>'); - } - - function tag(node) { - return node.nodeName.toLowerCase(); - } - - function testRe(re, lexeme) { - var match = re && re.exec(lexeme); - return match && match.index == 0; - } - - function blockLanguage(block) { - var classes = (block.className + ' ' + (block.parentNode ? block.parentNode.className : '')).split(/\s+/); - classes = classes.map(function(c) {return c.replace(/^lang(uage)?-/, '');}); - return classes.filter(function(c) {return getLanguage(c) || c == 'no-highlight';})[0]; - } - - function inherit(parent, obj) { - var result = {}; - for (var key in parent) - result[key] = parent[key]; - if (obj) - for (var key in obj) - result[key] = obj[key]; - return result; - }; - - /* Stream merging */ - - function nodeStream(node) { - var result = []; - (function _nodeStream(node, offset) { - for (var child = node.firstChild; child; child = child.nextSibling) { - if (child.nodeType == 3) - offset += child.nodeValue.length; - else if (tag(child) == 'br') - offset += 1; - else if (child.nodeType == 1) { - result.push({ - event: 'start', - offset: offset, - node: child - }); - offset = _nodeStream(child, offset); - result.push({ - event: 'stop', - offset: offset, - node: child - }); - } - } - return offset; - })(node, 0); - return result; - } - - function mergeStreams(original, highlighted, value) { - var processed = 0; - var result = ''; - var nodeStack = []; - - function selectStream() { - if (!original.length || !highlighted.length) { - return original.length ? original : highlighted; - } - if (original[0].offset != highlighted[0].offset) { - return (original[0].offset < highlighted[0].offset) ? original : highlighted; - } - - /* - To avoid starting the stream just before it should stop the order is - ensured that original always starts first and closes last: - - if (event1 == 'start' && event2 == 'start') - return original; - if (event1 == 'start' && event2 == 'stop') - return highlighted; - if (event1 == 'stop' && event2 == 'start') - return original; - if (event1 == 'stop' && event2 == 'stop') - return highlighted; - - ... which is collapsed to: - */ - return highlighted[0].event == 'start' ? original : highlighted; - } - - function open(node) { - function attr_str(a) {return ' ' + a.nodeName + '="' + escape(a.value) + '"';} - result += '<' + tag(node) + Array.prototype.map.call(node.attributes, attr_str).join('') + '>'; - } - - function close(node) { - result += ''; - } - - function render(event) { - (event.event == 'start' ? open : close)(event.node); - } - - while (original.length || highlighted.length) { - var stream = selectStream(); - result += escape(value.substr(processed, stream[0].offset - processed)); - processed = stream[0].offset; - if (stream == original) { - /* - On any opening or closing tag of the original markup we first close - the entire highlighted node stack, then render the original tag along - with all the following original tags at the same offset and then - reopen all the tags on the highlighted stack. - */ - nodeStack.reverse().forEach(close); - do { - render(stream.splice(0, 1)[0]); - stream = selectStream(); - } while (stream == original && stream.length && stream[0].offset == processed); - nodeStack.reverse().forEach(open); - } else { - if (stream[0].event == 'start') { - nodeStack.push(stream[0].node); - } else { - nodeStack.pop(); - } - render(stream.splice(0, 1)[0]); - } - } - return result + escape(value.substr(processed)); - } - - /* Initialization */ - - function compileLanguage(language) { - - function reStr(re) { - return (re && re.source) || re; - } - - function langRe(value, global) { - return RegExp( - reStr(value), - 'm' + (language.case_insensitive ? 'i' : '') + (global ? 'g' : '') - ); - } - - function compileMode(mode, parent) { - if (mode.compiled) - return; - mode.compiled = true; - - mode.keywords = mode.keywords || mode.beginKeywords; - if (mode.keywords) { - var compiled_keywords = {}; - - function flatten(className, str) { - if (language.case_insensitive) { - str = str.toLowerCase(); - } - str.split(' ').forEach(function(kw) { - var pair = kw.split('|'); - compiled_keywords[pair[0]] = [className, pair[1] ? Number(pair[1]) : 1]; - }); - } - - if (typeof mode.keywords == 'string') { // string - flatten('keyword', mode.keywords); - } else { - Object.keys(mode.keywords).forEach(function (className) { - flatten(className, mode.keywords[className]); - }); - } - mode.keywords = compiled_keywords; - } - mode.lexemesRe = langRe(mode.lexemes || /\b[A-Za-z0-9_]+\b/, true); - - if (parent) { - if (mode.beginKeywords) { - mode.begin = '\\b(' + mode.beginKeywords.split(' ').join('|') + ')\\b'; - } - if (!mode.begin) - mode.begin = /\B|\b/; - mode.beginRe = langRe(mode.begin); - if (!mode.end && !mode.endsWithParent) - mode.end = /\B|\b/; - if (mode.end) - mode.endRe = langRe(mode.end); - mode.terminator_end = reStr(mode.end) || ''; - if (mode.endsWithParent && parent.terminator_end) - mode.terminator_end += (mode.end ? '|' : '') + parent.terminator_end; - } - if (mode.illegal) - mode.illegalRe = langRe(mode.illegal); - if (mode.relevance === undefined) - mode.relevance = 1; - if (!mode.contains) { - mode.contains = []; - } - var expanded_contains = []; - mode.contains.forEach(function(c) { - if (c.variants) { - c.variants.forEach(function(v) {expanded_contains.push(inherit(c, v));}); - } else { - expanded_contains.push(c == 'self' ? mode : c); - } - }); - mode.contains = expanded_contains; - mode.contains.forEach(function(c) {compileMode(c, mode);}); - - if (mode.starts) { - compileMode(mode.starts, parent); - } - - var terminators = - mode.contains.map(function(c) { - return c.beginKeywords ? '\\.?(' + c.begin + ')\\.?' : c.begin; - }) - .concat([mode.terminator_end, mode.illegal]) - .map(reStr) - .filter(Boolean); - mode.terminators = terminators.length ? langRe(terminators.join('|'), true) : {exec: function(s) {return null;}}; - - mode.continuation = {}; - } - - compileMode(language); - } - - /* - Core highlighting function. Accepts a language name, or an alias, and a - string with the code to highlight. Returns an object with the following - properties: - - - relevance (int) - - value (an HTML string with highlighting markup) - - */ - function highlight(name, value, ignore_illegals, continuation) { - - function subMode(lexeme, mode) { - for (var i = 0; i < mode.contains.length; i++) { - if (testRe(mode.contains[i].beginRe, lexeme)) { - return mode.contains[i]; - } - } - } - - function endOfMode(mode, lexeme) { - if (testRe(mode.endRe, lexeme)) { - return mode; - } - if (mode.endsWithParent) { - return endOfMode(mode.parent, lexeme); - } - } - - function isIllegal(lexeme, mode) { - return !ignore_illegals && testRe(mode.illegalRe, lexeme); - } - - function keywordMatch(mode, match) { - var match_str = language.case_insensitive ? match[0].toLowerCase() : match[0]; - return mode.keywords.hasOwnProperty(match_str) && mode.keywords[match_str]; - } - - function buildSpan(classname, insideSpan, leaveOpen, noPrefix) { - var classPrefix = noPrefix ? '' : options.classPrefix, - openSpan = ''; - - return openSpan + insideSpan + closeSpan; - } - - function processKeywords() { - if (!top.keywords) - return escape(mode_buffer); - var result = ''; - var last_index = 0; - top.lexemesRe.lastIndex = 0; - var match = top.lexemesRe.exec(mode_buffer); - while (match) { - result += escape(mode_buffer.substr(last_index, match.index - last_index)); - var keyword_match = keywordMatch(top, match); - if (keyword_match) { - relevance += keyword_match[1]; - result += buildSpan(keyword_match[0], escape(match[0])); - } else { - result += escape(match[0]); - } - last_index = top.lexemesRe.lastIndex; - match = top.lexemesRe.exec(mode_buffer); - } - return result + escape(mode_buffer.substr(last_index)); - } - - function processSubLanguage() { - if (top.subLanguage && !languages[top.subLanguage]) { - return escape(mode_buffer); - } - var result = top.subLanguage ? highlight(top.subLanguage, mode_buffer, true, top.continuation.top) : highlightAuto(mode_buffer); - // Counting embedded language score towards the host language may be disabled - // with zeroing the containing mode relevance. Usecase in point is Markdown that - // allows XML everywhere and makes every XML snippet to have a much larger Markdown - // score. - if (top.relevance > 0) { - relevance += result.relevance; - } - if (top.subLanguageMode == 'continuous') { - top.continuation.top = result.top; - } - return buildSpan(result.language, result.value, false, true); - } - - function processBuffer() { - return top.subLanguage !== undefined ? processSubLanguage() : processKeywords(); - } - - function startNewMode(mode, lexeme) { - var markup = mode.className? buildSpan(mode.className, '', true): ''; - if (mode.returnBegin) { - result += markup; - mode_buffer = ''; - } else if (mode.excludeBegin) { - result += escape(lexeme) + markup; - mode_buffer = ''; - } else { - result += markup; - mode_buffer = lexeme; - } - top = Object.create(mode, {parent: {value: top}}); - } - - function processLexeme(buffer, lexeme) { - - mode_buffer += buffer; - if (lexeme === undefined) { - result += processBuffer(); - return 0; - } - - var new_mode = subMode(lexeme, top); - if (new_mode) { - result += processBuffer(); - startNewMode(new_mode, lexeme); - return new_mode.returnBegin ? 0 : lexeme.length; - } - - var end_mode = endOfMode(top, lexeme); - if (end_mode) { - var origin = top; - if (!(origin.returnEnd || origin.excludeEnd)) { - mode_buffer += lexeme; - } - result += processBuffer(); - do { - if (top.className) { - result += ''; - } - relevance += top.relevance; - top = top.parent; - } while (top != end_mode.parent); - if (origin.excludeEnd) { - result += escape(lexeme); - } - mode_buffer = ''; - if (end_mode.starts) { - startNewMode(end_mode.starts, ''); - } - return origin.returnEnd ? 0 : lexeme.length; - } - - if (isIllegal(lexeme, top)) - throw new Error('Illegal lexeme "' + lexeme + '" for mode "' + (top.className || '') + '"'); - - /* - Parser should not reach this point as all types of lexemes should be caught - earlier, but if it does due to some bug make sure it advances at least one - character forward to prevent infinite looping. - */ - mode_buffer += lexeme; - return lexeme.length || 1; - } - - var language = getLanguage(name); - if (!language) { - throw new Error('Unknown language: "' + name + '"'); - } - - compileLanguage(language); - var top = continuation || language; - var result = ''; - for(var current = top; current != language; current = current.parent) { - if (current.className) { - result += buildSpan(current.className, result, true); - } - } - var mode_buffer = ''; - var relevance = 0; - try { - var match, count, index = 0; - while (true) { - top.terminators.lastIndex = index; - match = top.terminators.exec(value); - if (!match) - break; - count = processLexeme(value.substr(index, match.index - index), match[0]); - index = match.index + count; - } - processLexeme(value.substr(index)); - for(var current = top; current.parent; current = current.parent) { // close dangling modes - if (current.className) { - result += ''; - } - }; - return { - relevance: relevance, - value: result, - language: name, - top: top - }; - } catch (e) { - if (e.message.indexOf('Illegal') != -1) { - return { - relevance: 0, - value: escape(value) - }; - } else { - throw e; - } - } - } - - /* - Highlighting with language detection. Accepts a string with the code to - highlight. Returns an object with the following properties: - - - language (detected language) - - relevance (int) - - value (an HTML string with highlighting markup) - - second_best (object with the same structure for second-best heuristically - detected language, may be absent) - - */ - function highlightAuto(text, languageSubset) { - languageSubset = languageSubset || options.languages || Object.keys(languages); - var result = { - relevance: 0, - value: escape(text) - }; - var second_best = result; - languageSubset.forEach(function(name) { - if (!getLanguage(name)) { - return; - } - var current = highlight(name, text, false); - current.language = name; - if (current.relevance > second_best.relevance) { - second_best = current; - } - if (current.relevance > result.relevance) { - second_best = result; - result = current; - } - }); - if (second_best.language) { - result.second_best = second_best; - } - return result; - } - - /* - Post-processing of the highlighted markup: - - - replace TABs with something more useful - - replace real line-breaks with '
    ' for non-pre containers - - */ - function fixMarkup(value) { - if (options.tabReplace) { - value = value.replace(/^((<[^>]+>|\t)+)/gm, function(match, p1, offset, s) { - return p1.replace(/\t/g, options.tabReplace); - }); - } - if (options.useBR) { - value = value.replace(/\n/g, '
    '); - } - return value; - } - - /* - Applies highlighting to a DOM node containing code. Accepts a DOM node and - two optional parameters for fixMarkup. - */ - function highlightBlock(block) { - var text = options.useBR ? block.innerHTML - .replace(/\n/g,'').replace(/
    |
    ]*>/g, '\n').replace(/<[^>]*>/g,'') - : block.textContent; - var language = blockLanguage(block); - if (language == 'no-highlight') - return; - var result = language ? highlight(language, text, true) : highlightAuto(text); - var original = nodeStream(block); - if (original.length) { - var pre = document.createElementNS('http://www.w3.org/1999/xhtml', 'pre'); - pre.innerHTML = result.value; - result.value = mergeStreams(original, nodeStream(pre), text); - } - result.value = fixMarkup(result.value); - - block.innerHTML = result.value; - block.className += ' hljs ' + (!language && result.language || ''); - block.result = { - language: result.language, - re: result.relevance - }; - if (result.second_best) { - block.second_best = { - language: result.second_best.language, - re: result.second_best.relevance - }; - } - } - - var options = { - classPrefix: 'hljs-', - tabReplace: null, - useBR: false, - languages: undefined - }; - - /* - Updates highlight.js global options with values passed in the form of an object - */ - function configure(user_options) { - options = inherit(options, user_options); - } - - /* - Applies highlighting to all
    ..
    blocks on a page. - */ - function initHighlighting() { - if (initHighlighting.called) - return; - initHighlighting.called = true; - - var blocks = document.querySelectorAll('pre code'); - Array.prototype.forEach.call(blocks, highlightBlock); - } - - /* - Attaches highlighting to the page load event. - */ - function initHighlightingOnLoad() { - addEventListener('DOMContentLoaded', initHighlighting, false); - addEventListener('load', initHighlighting, false); - } - - var languages = {}; - var aliases = {}; - - function registerLanguage(name, language) { - var lang = languages[name] = language(this); - if (lang.aliases) { - lang.aliases.forEach(function(alias) {aliases[alias] = name;}); - } - } - - function listLanguages() { - return Object.keys(languages); - } - - function getLanguage(name) { - return languages[name] || languages[aliases[name]]; - } - - /* Interface definition */ - - this.highlight = highlight; - this.highlightAuto = highlightAuto; - this.fixMarkup = fixMarkup; - this.highlightBlock = highlightBlock; - this.configure = configure; - this.initHighlighting = initHighlighting; - this.initHighlightingOnLoad = initHighlightingOnLoad; - this.registerLanguage = registerLanguage; - this.listLanguages = listLanguages; - this.getLanguage = getLanguage; - this.inherit = inherit; - - // Common regexps - this.IDENT_RE = '[a-zA-Z][a-zA-Z0-9_]*'; - this.UNDERSCORE_IDENT_RE = '[a-zA-Z_][a-zA-Z0-9_]*'; - this.NUMBER_RE = '\\b\\d+(\\.\\d+)?'; - this.C_NUMBER_RE = '(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)'; // 0x..., 0..., decimal, float - this.BINARY_NUMBER_RE = '\\b(0b[01]+)'; // 0b... - this.RE_STARTERS_RE = '!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~'; - - // Common modes - this.BACKSLASH_ESCAPE = { - begin: '\\\\[\\s\\S]', relevance: 0 - }; - this.APOS_STRING_MODE = { - className: 'string', - begin: '\'', end: '\'', - illegal: '\\n', - contains: [this.BACKSLASH_ESCAPE] - }; - this.QUOTE_STRING_MODE = { - className: 'string', - begin: '"', end: '"', - illegal: '\\n', - contains: [this.BACKSLASH_ESCAPE] - }; - this.PHRASAL_WORDS_MODE = { - begin: /\b(a|an|the|are|I|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such)\b/ - }; - this.C_LINE_COMMENT_MODE = { - className: 'comment', - begin: '//', end: '$', - contains: [this.PHRASAL_WORDS_MODE] - }; - this.C_BLOCK_COMMENT_MODE = { - className: 'comment', - begin: '/\\*', end: '\\*/', - contains: [this.PHRASAL_WORDS_MODE] - }; - this.HASH_COMMENT_MODE = { - className: 'comment', - begin: '#', end: '$', - contains: [this.PHRASAL_WORDS_MODE] - }; - this.NUMBER_MODE = { - className: 'number', - begin: this.NUMBER_RE, - relevance: 0 - }; - this.C_NUMBER_MODE = { - className: 'number', - begin: this.C_NUMBER_RE, - relevance: 0 - }; - this.BINARY_NUMBER_MODE = { - className: 'number', - begin: this.BINARY_NUMBER_RE, - relevance: 0 - }; - this.CSS_NUMBER_MODE = { - className: 'number', - begin: this.NUMBER_RE + '(' + - '%|em|ex|ch|rem' + - '|vw|vh|vmin|vmax' + - '|cm|mm|in|pt|pc|px' + - '|deg|grad|rad|turn' + - '|s|ms' + - '|Hz|kHz' + - '|dpi|dpcm|dppx' + - ')?', - relevance: 0 - }; - this.REGEXP_MODE = { - className: 'regexp', - begin: /\//, end: /\/[gim]*/, - illegal: /\n/, - contains: [ - this.BACKSLASH_ESCAPE, - { - begin: /\[/, end: /\]/, - relevance: 0, - contains: [this.BACKSLASH_ESCAPE] - } - ] - }; - this.TITLE_MODE = { - className: 'title', - begin: this.IDENT_RE, - relevance: 0 - }; - this.UNDERSCORE_TITLE_MODE = { - className: 'title', - begin: this.UNDERSCORE_IDENT_RE, - relevance: 0 - }; -}; diff --git a/share/nitdoc/js/lib/nit.js b/share/nitdoc/js/lib/nit.js deleted file mode 100644 index 1b4aff3..0000000 --- a/share/nitdoc/js/lib/nit.js +++ /dev/null @@ -1,144 +0,0 @@ -/* This file is part of NIT ( http://www.nitlanguage.org ). - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - Documentation generator for the nit language. - Generate API documentation in HTML format from nit source code. -*/ - -hljs.registerLanguage('nit', function(hljs) { - var METHOD_RE = '[a-z_]\\w*[!?=]?|[-+~]\\@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?'; - var KEYWORDS = { - keyword: 'abort abstract and as assert break class continue do else end enum extern for fun ' + - 'if import in init interface intern intrude is isa isset label loop module new nullable not ' + - 'once or protected private redef return self super then type universal var ' + - 'when while writable', - literal: "true false null" - }; - var COMMENT = { - className: 'comment', - begin: '#', end: '$', - }; - var SUBST = { - className: 'subst', - begin: '{', end: '}', - keywords: KEYWORDS - }; - var STRING = { - className: 'string', - contains: [hljs.BACKSLASH_ESCAPE, SUBST], - variants: [ - {begin: /"/, end: /"/}, - ] - }; - var CHAR = { - className: 'char', - contains: [hljs.BACKSLASH_ESCAPE, SUBST], - begin: /'/, end: /'/, - }; - var TYPE = { - className: 'type', - begin: '[A-Z]\\w*' - } - var PARAMS = { - className: 'params', - begin: '\\(', end: '\\)', - keywords: KEYWORDS, - contains: [TYPE] - }; - var RET_TYPE = { - className: 'rettype', - begin: ':', end: '$|do|is|=', - keywords: 'nullable', - returnEnd: true, - contains: [TYPE] - } - var DO_BLOCK = { - className: 'block', - begin: 'do', end: '$|end', - keywords: KEYWORDS - } - var IS_BLOCK = { - className: 'modifiers', - begin: 'is', end: '$', - keywords: KEYWORDS - } - var CONTAINS = [ - STRING, - CHAR, - COMMENT, - TYPE, - { - className: 'module', - beginKeywords: 'module', end: '$', - contains: [ - hljs.inherit(hljs.TITLE_MODE, {begin: '[a-z_]\\w*'}), - COMMENT - ] - }, - { - className: 'import', - begin: '(intrude )?import', end: '$', - keywords: 'intrude import', - contains: [ - { - className: 'module', - begin: '[a-z_]\\w*' - }, - COMMENT - ] - }, - { - className: 'class', - begin: '(redef |private |protected )?(abstract )?(class|interface)', end: '$', - keywords: 'redef private protected abstract class interface', - contains: [ - hljs.inherit(hljs.TITLE_MODE, {begin: '[A-Z]\\w*'}), - { - className: 'super', - begin: '\\bsuper', end: '$', - keywords: 'super', - contains: [TYPE] - }, - COMMENT - ] - }, - { - className: 'fun', - begin: '(redef |private |protected )?(fun|init|type)\\b', end: '$', - keywords: KEYWORDS, - contains: [ - PARAMS, - RET_TYPE, - DO_BLOCK, - IS_BLOCK, - { - className: 'title', - begin: '\\b[a-zA-Z_][a-zA-Z_]*\\b' - }, - COMMENT - ] - }, - { - className: 'number', - begin: '(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b', - relevance: 0 - } - ]; - SUBST.contains = CONTAINS; - - return { - keywords: KEYWORDS, - contains: CONTAINS - }; -}); diff --git a/share/nitdoc/js/lib/utils.js b/share/nitdoc/js/lib/utils.js deleted file mode 100644 index 26304d8..0000000 --- a/share/nitdoc/js/lib/utils.js +++ /dev/null @@ -1,204 +0,0 @@ -/* This file is part of NIT ( http://www.nitlanguage.org ). - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - Documentation generator for the nit language. - Generate API documentation in HTML format from nit source code. -*/ - -/* - * Utils module - */ -String.prototype.startsWith = function(prefix, caseSensitive) { - if(caseSensitive) { - return this.toUpperCase().indexOf(prefix.toUpperCase()) === 0; - } - return this.indexOf(prefix) === 0; -} - -// Compare two strings using Sorensen-Dice Coefficient -// see: http://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient -String.prototype.dice = function(other) { - var length1 = this.length - 1; - var length2 = other.length - 1; - if(length1 < 1 || length2 < 1) return 0; - - var bigrams2 = []; - for(var i = 0; i < length2; i++) { - bigrams2.push(other.substr(i, 2)); - } - - var intersection = 0; - for(var i = 0; i < length1; i++) { - var bigram1 = this.substr(i, 2); - for(var j = 0; j < length2; j++) { - if(bigram1 == bigrams2[j]) { - intersection++; - bigrams2[j] = null; - break; - } - } - } - return (2.0 * intersection) / (length1 + length2); -} - -/* base64 */ - -String.prototype._keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; - -// public method for encoding -String.prototype.base64Encode = function () { - var output = ""; - var chr1, chr2, chr3, enc1, enc2, enc3, enc4; - var i = 0; - - input = this._utf8_encode(); - - while (i < input.length) { - - chr1 = input.charCodeAt(i++); - chr2 = input.charCodeAt(i++); - chr3 = input.charCodeAt(i++); - - enc1 = chr1 >> 2; - enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); - enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); - enc4 = chr3 & 63; - - if (isNaN(chr2)) { - enc3 = enc4 = 64; - } else if (isNaN(chr3)) { - enc4 = 64; - } - - output = output + - this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) + - this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4); - - } - return output; -}; - -// public method for decoding -String.prototype.base64Decode = function () { - var output = ""; - var chr1, chr2, chr3; - var enc1, enc2, enc3, enc4; - var i = 0; - - input = this.replace(/[^A-Za-z0-9\+\/\=]/g, ""); - - while (i < input.length) { - - enc1 = this._keyStr.indexOf(input.charAt(i++)); - enc2 = this._keyStr.indexOf(input.charAt(i++)); - enc3 = this._keyStr.indexOf(input.charAt(i++)); - enc4 = this._keyStr.indexOf(input.charAt(i++)); - - chr1 = (enc1 << 2) | (enc2 >> 4); - chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); - chr3 = ((enc3 & 3) << 6) | enc4; - - output = output + String.fromCharCode(chr1); - - if (enc3 != 64) { - output = output + String.fromCharCode(chr2); - } - if (enc4 != 64) { - output = output + String.fromCharCode(chr3); - } - - } - return output._utf8_decode();; -}; - -// private method for UTF-8 encoding -String.prototype._utf8_encode = function () { - string = this.replace(/\r\n/g,"\n"); - var utftext = ""; - - for (var n = 0; n < string.length; n++) { - - var c = string.charCodeAt(n); - - if (c < 128) { - utftext += String.fromCharCode(c); - } - else if((c > 127) && (c < 2048)) { - utftext += String.fromCharCode((c >> 6) | 192); - utftext += String.fromCharCode((c & 63) | 128); - } - else { - utftext += String.fromCharCode((c >> 12) | 224); - utftext += String.fromCharCode(((c >> 6) & 63) | 128); - utftext += String.fromCharCode((c & 63) | 128); - } - - } - return utftext; -}; - -// private method for UTF-8 decoding -String.prototype._utf8_decode = function () { - var string = ""; - var i = 0; - var c = c1 = c2 = 0; - - while ( i < this.length ) { - - c = this.charCodeAt(i); - - if (c < 128) { - string += String.fromCharCode(c); - i++; - } - else if((c > 191) && (c < 224)) { - c2 = this.charCodeAt(i+1); - string += String.fromCharCode(((c & 31) << 6) | (c2 & 63)); - i += 2; - } - else { - c2 = this.charCodeAt(i+1); - c3 = this.charCodeAt(i+2); - string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); - i += 3; - } - - } - return string; -}; - -// JQuery Case Insensitive :icontains selector -$.expr[':'].icontains = function(obj, index, meta, stack){ - return (obj.textContent.replace(/\[[0-9]+\]/g, "") || obj.innerText.replace(/\[[0-9]+\]/g, "") || jQuery(obj).text().replace(/\[[0-9]+\]/g, "") || '').toLowerCase().indexOf(meta[3].toLowerCase()) >= 0; -}; - -var Utils = { - // Extract anchor part (after #) from URL string - extractAnchor: function(url) { - var index = url.indexOf("#"); - if (index >= 0) { - return url.substring(index + 1); - } - return null; - }, - - delayEvent: function(handler, event) { - if(this.delayEvent.timeout) { - clearTimeout(this.delayEvent.timeout); - } - this.delayEvent.timeout = setTimeout(function() { - handler.call(event); - }, 50); - } -}; diff --git a/share/nitdoc/js/nitdoc.quicksearch.js b/share/nitdoc/js/nitdoc.quicksearch.js new file mode 100644 index 0000000..746d2e6 --- /dev/null +++ b/share/nitdoc/js/nitdoc.quicksearch.js @@ -0,0 +1,384 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Nitdoc QuickSearch widget */ + +$.widget("nitdoc.quicksearch", { + + options: { + list: {}, // List of raw results generated by nitdoc tool + fieldAttrs: { + autocomplete: "off", + }, + maxSize: 10 + }, + + _create: function() { + // set widget options + this.element.attr(this.options.fieldAttrs); + // event dispatch + this._on(this.element, { + "keydown": this._doKeyDown, + "keyup": this._doKeyUp, + "input": this._doInput + }); + // add result table element once + this._popup = $("
    ") + .attr("id", "nitdoc-qs-popup") + .css("position", "absolute") + .css("z-index", 10000) + .hide(); + $("body").append(this._popup); + // make table disappear when a click occurs outside + $(document).click($.proxy(this.close, this)); + this._autosizeTable(); + }, + + /* events */ + + _doKeyDown: function(event) { + switch(event.keyCode) { + case 38: // Up + this._selectPrev(); + return false; + case 40: // Down + this._selectNext(); + return false; + default: + return true; + } + }, + + _doKeyUp: function(event) { + switch(event.keyCode) { + case 38: // Up + case 40: // Down + break; + case 13: // Enter + this._loadResult(); + return false; + case 27: // Escape + this.element.blur(); + this.close(); + return true; + default: // Other keys + return true; + } + }, + + _doInput: function(event) { + Utils.delayEvent($.proxy(this.search, this)); + }, + + /* Result lookup */ + + _getResults: function(query) { + var results = []; + + // Prefix matches + var prefix_matches = []; + for(var entry in this.options.list) { + if(!entry.startsWith(query, true)) { + continue; + } + var cat = { + name: entry, + entries: this.options.list[entry] + }; + prefix_matches.push(cat); + + if(entry == query) { + cat.rank = 10; + } else if(entry.toUpperCase() == query.toUpperCase()) { + cat.rank = 5; + } else if(entry[0] == query[0]) { + cat.rank = 1.1 + query.dice(entry); + } else { + cat.rank = 1 + query.dice(entry); + } + } + if(prefix_matches.length > 0) { + prefix_matches.sort(this._rankSorter); + for(var i in prefix_matches) { + var cat = prefix_matches[i]; + for(var j in cat.entries) { + var entry = cat.entries[j]; + entry.name = cat.name; + results.push(entry); + } + } + return results; + } + + // Partial matches + var partial_matches = []; + for(var entry in this.options.list) { + var cat = { + name: entry, + entries: this.options.list[entry] + } + cat.rank = query.dice(entry); + if(cat.rank > 0) { + partial_matches.push(cat); + } + } + if(partial_matches.length > 0) { + partial_matches.sort(this._rankSorter); + for(var i in partial_matches) { + var cat = partial_matches[i]; + for(var j in cat.entries) { + var entry = cat.entries[j]; + entry.name = cat.name; + results.push(entry); + } + } + } + + return results; + }, + + _rankSorter: function(a, b){ + if(a.rank < b.rank) { + return 1; + } else if(a.rank > b.rank) { + return -1; + } + return 0; + }, + + /* Results table */ + + search: function() { + var query = this.element.val(); + if(query) { + var results = this._getResults(query); + this.open(query, results); + } + }, + + open: function(query, results) { + this._popup.empty(); + this._cards = []; + this._index = -1; + + if(results.length == 0) { + this.addNoResultCard(); + } + + if(results.length >= this.options.maxSize) { + this.addOverflowUp(false); + } + + for(var i in results) { + var result = results[i]; + this.addCard(result.name, result.txt, result.url, this.options.rowCatClass) + } + + if(results.length >= this.options.maxSize) { + this.addOverflowDown(true); + } + + if(results.length > 0) { + this._setIndex(0); + } + + this._popup.show(); + this._autosizeTable(); + }, + + close: function(target) { + if(target != this.element && target != this._popup) { + this._popup.hide(); + } + }, + + addCard: function(name, txt, url, cls) { + var card = $("
    ") + .addClass("qs-card") + .addClass("qs-result") + .data("searchDetails", {name: name, url: url}) + .data("index", this._cards.length) + .append( + $("

    ") + .html(name) + .addClass(cls) + ) + .append( + $("") + .html(txt) + .addClass("qs-info") + ) + .mouseover($.proxy(this._mouseOverRow, this)) + .click($.proxy(this._clickRow, this)) + this._cards.push(card); + if(this._cards.length >= this.options.maxSize) { + card.hide(); + } + this._popup.append(card); + }, + + addOverflowUp: function(active) { + this._popup.append( + $("
    ") + .addClass("qs-overflow") + .addClass("qs-overflow-up") + .addClass(active ? "qs-overflow-active": "") + .html("▲") + .click($.proxy(this._clickPrev, this)) + ); + }, + + addOverflowDown: function(active) { + this._popup.append( + $("
    ") + .addClass("qs-overflow") + .addClass("qs-overflow-down") + .addClass(active ? "qs-overflow-active": "") + .html("▼") + .click($.proxy(this._clickNext, this)) + ); + }, + + addNoResultCard: function() { + var card = $("
    ") + .addClass("qs-card qs-noresult") + .html("Sorry, there is no match..."); + this._popup.append(card); + }, + + _autosizeTable: function() { + this._popup.position({ + my: "left top", + at: "left bottom", + of: this.element + }); + this._popup + .css("min-width", this.element.outerWidth()) + .css("max-width", this.element.outerWidth()); + }, + + _hasIndex: function(index) { + return index >= 0 && index < this._cards.length; + }, + + _hasPrev: function(index) { + return index - 1 >= 0; + }, + + _hasNext: function(index) { + return index + 1 < this._cards.length; + }, + + _setIndex: function(index) { + if(this._hasIndex(this._index)) { + this._cards[this._index].removeClass("qs-active"); + } + this._index = index; + if(this._hasIndex(this._index)) { + this._cards[this._index].addClass("qs-active"); + } + }, + + _selectPrev: function() { + if(this._hasPrev(this._index)) { + this._setIndex(this._index - 1); + if(!this._cards[this._index].is(":visible")) { + this._popup.find(".qs-result:visible").last().hide(); + this._popup.find(".qs-overflow-down").addClass("qs-overflow-active"); + this._cards[this._index].show(); + if(!this._hasPrev(this._index)) { + this._popup.find(".qs-overflow-up").removeClass("qs-overflow-active"); + } + } + } else { + } + }, + + _selectNext: function() { + if(this._hasNext(this._index)) { + this._setIndex(this._index + 1); + if(!this._cards[this._index].is(":visible")) { + this._popup.find(".qs-result:visible").first().hide(); + this._popup.find(".qs-overflow-up").addClass("qs-overflow-active"); + this._cards[this._index].show(); + if(!this._hasNext(this._index)) { + this._popup.find(".qs-overflow-down").removeClass("qs-overflow-active"); + } + } + } + }, + + // Load selected search result page + _loadResult: function() { + if(this._index > -1) { + window.location = this._cards[this._index].data("searchDetails").url; + return; + } + if(this.element.val().length == 0) { return; } + + window.location = this.options.gotoPage + "#q=" + this.element.val(); + if(window.location.href.indexOf(this.options.gotoPage) > -1) { + location.reload(); + } + }, + + /* table events */ + + _clickNext: function(event) { + event.stopPropagation(); + this._selectNext(); + }, + + _clickPrev: function(event) { + event.stopPropagation(); + this._selectPrev(); + }, + + _clickRow: function(event) { + window.location = $(event.currentTarget).data("searchDetails")["url"]; + }, + + _mouseOverRow: function(event) { + this._setIndex($(event.currentTarget).data("index")); + } +}); + +var searchField = $("") +.addClass("form-control search-input") +.attr({ + id: "nitdoc-qs-field", + type: "text", + placeholder: "Search..." +}) + +$("#search-placeholder").append( + $("
    ") + .addClass("navbar-form navbar-right") + .on("submit", function() { return false; }) + .css("margin-bottom", 0) + .css("margin-top", 0) + .append( + $("
    ") + .addClass("form-group has-icon") + .append(searchField) + .append( + $("") + .addClass("glyphicon glyphicon-search form-control-icon text-muted") + ) + ) +); + +searchField.quicksearch({ + list: this.nitdocQuickSearchRawList +}); diff --git a/share/nitdoc/js/nitdoc.utils.js b/share/nitdoc/js/nitdoc.utils.js new file mode 100644 index 0000000..ac19c29 --- /dev/null +++ b/share/nitdoc/js/nitdoc.utils.js @@ -0,0 +1,109 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Utils module */ + +String.prototype.startsWith = function(prefix, caseSensitive) { + if(caseSensitive) { + return this.toUpperCase().indexOf(prefix.toUpperCase()) === 0; + } + return this.indexOf(prefix) === 0; +} + +// Compare two strings using Sorensen-Dice Coefficient +// see: http://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient +String.prototype.dice = function(other) { + var length1 = this.length - 1; + var length2 = other.length - 1; + if(length1 < 1 || length2 < 1) return 0; + + var bigrams2 = []; + for(var i = 0; i < length2; i++) { + bigrams2.push(other.substr(i, 2)); + } + + var intersection = 0; + for(var i = 0; i < length1; i++) { + var bigram1 = this.substr(i, 2); + for(var j = 0; j < length2; j++) { + if(bigram1 == bigrams2[j]) { + intersection++; + bigrams2[j] = null; + break; + } + } + } + return (2.0 * intersection) / (length1 + length2); +} + +var Utils = { + delayEvent: function(handler, event) { + if(this.delayEvent.timeout) { + clearTimeout(this.delayEvent.timeout); + } + this.delayEvent.timeout = setTimeout(function() { + handler.call(event); + }, 100); + }, + + scrollTo: function(target) { + var element = $(target); + if(element[0]) { + $("body, html").animate({ + scrollTop: element.offset().top - 60 + }); + } + }, + + openTab: function(e) { + // Open tab + var url = document.location.toString(); + if (url.match('#')) { + var hash = url.split('#')[1]; + var element = $('.nav-tabs a[href="#' + hash + '"]'); + if(element[0]) { + element.tab('show'); + } else { + Utils.scrollTo('#' + hash); + } + } + + // Jump to id + var obj = new URL(url); + var arg = obj.searchParams.get("def"); + if(arg) { + var def = '#' + arg; + $('.card.active').removeClass('active'); + $(def).addClass('active'); + $(def).find('.collapse').collapse(); + Utils.scrollTo(def); + } + } +}; + +Utils.openTab(); + +window.addEventListener("hashchange", Utils.openTab, false); + +// Scroll on hash click +$('.summary a[href*=#]').on('click', function(e) { + e.preventDefault(); + Utils.scrollTo(e.currentTarget.hash); + history.pushState({}, '', e.currentTarget.hash); +}); + +// Change hash for page-reload +$('.nav-tabs a[href]').on('shown.bs.tab', function (e) { + history.pushState({}, '', e.target.hash) +}); diff --git a/share/nitdoc/js/plugins/filtering.js b/share/nitdoc/js/plugins/filtering.js deleted file mode 100644 index fa0f12e..0000000 --- a/share/nitdoc/js/plugins/filtering.js +++ /dev/null @@ -1,158 +0,0 @@ -/* This file is part of NIT ( http://www.nitlanguage.org ). - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - Documentation generator for the nit language. - Generate API documentation in HTML format from nit source code. -*/ - -/* - * Nitdoc Filtering - * - * Allow user to filter sidebar entries and search page - */ -var Filtering = { - - // Allow user to filter sidebar box entries by name - enableSidebarTextFilters: function(filterSelector) { - var div = $(document.createElement("div")) - .addClass("nitdoc-ui-filter") - .append( - $(document.createElement("input")) - .addClass("nitdoc-ui-filter-field") - .addClass("nitdoc-ui-filter-field-notused") - .attr("type", "text") - .attr("value", "filter...") - .keyup(function() { - var box = $(this).parents("nav.filterable"); - var value = $(this).val(); - box.find("ul li:not(:icontains('" + value + "'))").hide(); - box.find("ul li:icontains('" + value + "')").show(); - }) - .focusout(function() { - if($(this).val() == "") { - $(this).addClass("nitdoc-ui-filter-field-notused"); - $(this).val("filter..."); - } - }) - .focusin(function() { - if($(this).val() == "filter...") { - $(this).removeClass("nitdoc-ui-filter-field-notused"); - $(this).val(""); - } - }) - ); - $(filterSelector).after(div); - this.preloadSidebarTextFilters(); - }, - - // Prealod filters using search query - preloadSidebarTextFilters: function() { - var anchor = Utils.extractAnchor(document.location.hash); - if(!anchor || anchor.indexOf("q=") == -1) return; - - var query = anchor.substring(2); - if(!query) return; - - $(".nitdoc-ui-filter input:text") - .val(query) - .removeClass("nitdoc-ui-notused") - .trigger("keyup"); - }, - - // Allow user to filter side bar box entries by Introduced/Refined/inHerited type - enableSidebarTypeFilters: function(filterSelector) { - var box = $(filterSelector); - var types = {}; - - box.find("li").each(function() { - var span = $(this).find("span:first"); - if(!types[span.html()]) types[span.html()] = { - title: span.attr("title"), - class: $(this).attr("class") - } - }); - - for(var type in types) { - var a = $(document.createElement("a")) - .addClass("nitdoc-ui-filter-link") - .html(type) - .attr("title", "Hide " + types[type].title) - .attr("data-filter-class", types[type].class) - .toggle( - function() { - var hclass = $(this).attr("data-filter-class"); - $(this).parents(filterSelector).find("li." + hclass).hide(); - $(this).addClass("nitdoc-ui-filter-hidden") - }, - function() { - var hclass = $(this).attr("data-filter-class"); - $(this).parents(filterSelector).find("li." + hclass).show(); - $(this).removeClass("nitdoc-ui-filter-hidden") - } - ) - $(filterSelector).find(".nitdoc-ui-filter").append(a); - } - }, - - // Allow user to filter sidebar box entries by name - enableSearchPageField: function(filterSelector) { - var div = $(document.createElement("div")) - .addClass("nitdoc-ui-searchpage-filter") - .append( - $(document.createElement("input")) - .addClass("nitdoc-ui-searchpage-field") - .addClass("nitdoc-ui-filter-field-notused") - .attr("type", "text") - .attr("value", "filter...") - .keyup(function() { - var box = $(this).parents(".content.fullpage").find("article.filterable"); - var value = $(this).val(); - box.find("ul li:not(:icontains('" + value + "'))").hide(); - box.find("ul li:icontains('" + value + "')").show(); - }) - .focusout(function() { - if($(this).val() == "") { - $(this).addClass("nitdoc-ui-filter-field-notused"); - $(this).val("filter..."); - } - }) - .focusin(function() { - if($(this).val() == "filter...") { - $(this).removeClass("nitdoc-ui-filter-field-notused"); - $(this).val(""); - } - }) - ); - $(filterSelector).after(div); - this.preloadSearchPageField(); - }, - - // Prealod filter using search query - preloadSearchPageField: function() { - var anchor = Utils.extractAnchor(document.location.hash); - if(!anchor || anchor.indexOf("q=") == -1) return; - - var query = anchor.substring(2); - if(!query) return; - - $(".nitdoc-ui-searchpage-field") - .val(query) - .removeClass("nitdoc-ui-notused") - .trigger("keyup"); - } -}; - -Filtering.enableSidebarTextFilters("nav.filterable h3"); -Filtering.enableSidebarTypeFilters("nav.filterable"); -Filtering.enableSearchPageField(".content.fullpage h1:contains('Search')"); diff --git a/share/nitdoc/js/plugins/github.js b/share/nitdoc/js/plugins/github.js deleted file mode 100644 index c77c0d0..0000000 --- a/share/nitdoc/js/plugins/github.js +++ /dev/null @@ -1,593 +0,0 @@ -/* This file is part of NIT ( http://www.nitlanguage.org ). - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - Documentation generator for the nit language. - Generate API documentation in HTML format from nit source code. -*/ - -/* - * Nitdoc.Github comment edition module - * - * Allows user to modify source code comments directly from the Nitdoc - */ -define([ - "jquery", - "github-api", - "highlight", - "marked", - "nit", - "plugins/modalbox", - "plugins/github/loginbox", - "plugins/github/commentbox", - "utils" -], function($, GithubAPI, hljs, marked) { - var GithubUser = function(login, password, repo, branch) { - this.login = login; - this.password = password; - this.repo = repo; - this.auth = "Basic " + (login + ':' + password).base64Encode(); - this.branch = branch; - } - - var GithubUI = { - init: function(upstream, basesha1) { - console.info("Github plugin: init GitHub module (upstream: "+ upstream +", base: " + basesha1 + ")"); - this.origin = this._parseUpstream(upstream); - this._initMarked(); - // Add github menu - $("#topmenu>.container-fluid").append( - $("") - .attr({ - "id": "nitdoc-github-li", - "type": "button", - "class": "navbar-btn navbar-right btn-link", - "href": "#", - "data-container": "body", - "data-toggle": "popover", - "data-placement": "bottom", - "data-content": "bottom", - "data-html": "true", - }) - .loginbox() - //.loginbox("displayLogin") - .bind("loginbox_logoff", function() { - GithubUI.disactivate(); - }) - .bind("loginbox_login", function(event, infos) { - GithubUI._tryLoginFromCredentials(infos); - }) - ); - // check local session - this._tryLoginFromLocalSession(); - }, - - activate: function(user, origin) { - this.openedComments = 0; - this._saveSession(user); - $("#nitdoc-github-li").loginbox("displayLogout", origin, user); - this._attachCommentBoxes(); - this._reloadComments(); - - // Prevent page unload if there is comments in editing mode - $(window).on('beforeunload', function() { - if(GithubUI.openedComments > 0){ - return "There is uncommited modified comments. Are you sure you want to leave this page?"; - } - }); - }, - - disactivate: function() { - if(this.openedComments > 0){ - if(!confirm('There is uncommited modified comments. Are you sure you want to leave this page?')) { - return false; - } - } - - localStorage.clear(); - $("#nitdoc-github-li").loginbox("toggle"); - $("#nitdoc-github-li").loginbox("displayLogin"); - $(window).unbind('beforeunload'); - //window.location.reload(); - }, - - /* login */ - - _checkLoginInfos: function(infos) { - if(!infos.login || !infos.password || !infos.repo || !infos.branch) { - $("

    ") - .text("Please enter your GitHub username, password, repository and branch.") - .modalbox({ - title: "Sign in error", - isError: true - }) - .modalbox("open"); - return false; - } else { - return true; - } - }, - - _tryLoginFromCredentials: function(infos) { - if(this._checkLoginInfos(infos)) { - var isok = this._tryLogin(infos.login, infos.password, infos.repo, infos.branch); - if(isok === true) { - this.activate(this.user, this.origin); - } else { - if(isok == "error:login") { - $("

    ") - .text("The username, password, repo or branch you entered is incorrect.") - .modalbox({ - title: "Github sign in error", - isError: true - }) - .modalbox("open"); - } else if(isok == "error:sha") { - $("

    ") - .text("The provided Github repository must contain the base commit '" + this.origin.sha + "'.") - .modalbox({ - title: "Github base commit error", - isError: true - }) - .modalbox("open"); - } else if(isok == "error:profile") { - $("

    ") - .text("Please set your public name and email in your " + - "GitHub profile." + - "

    Your public profile informations are used to sign-off your commits.") - .modalbox({ - title: "Github profile error", - isError: true - }) - .modalbox("open"); - } - } - } - }, - - _tryLoginFromLocalSession: function() { - if(localStorage.user) { - var session = JSON.parse(localStorage.user); - var isok = this._tryLogin( - session.login, - session.password.base64Decode(), - session.repo, - session.branch - ); - if(isok === true) { - this.activate(this.user, this.origin); - } else { - console.debug("Github plugin: Session found but authentification failed"); - localStorage.clear(); - } - } else { - console.debug("Github plugin: No session found"); - } - }, - - _tryLogin: function(login, password, repo, branch) { - var tmpUser = new GithubUser(login, password, repo, branch); - if(!GithubAPI.login(tmpUser)) { - return "error:login"; - } - if(!tmpUser.infos.name || !tmpUser.infos.email) { - return "error:profile"; - } - var commit = GithubAPI.getCommit(tmpUser, this.origin.sha); - if(!commit || !commit.sha) { - return "error:sha"; - } - this.user = tmpUser; - return true; - }, - - _saveSession: function(user) { - localStorage.user = JSON.stringify({ - login: user.login, - password: user.password.base64Encode(), - repo: user.repo, - branch: user.branch, - }); - // check local storage synchro with branch - if(localStorage.base != this.origin.sha) { - console.log("Base changed: cleaned cache"); - localStorage.requests = "[]"; - localStorage.base = this.origin.sha; - } - }, - - /* html decoration */ - - // Attach edit button on each comment - _attachCommentBoxes: function() { - $("textarea.baseComment").each(function() { - $(this).commentbox(); - - var isNew = false; - if(!$(this).val()) { - isNew = true; - $(this).nextAll(".info:first").find(".noComment").hide() - $(this).nextAll(".info:first").before( - $("

    ") - .hide() - .addClass("comment") - .append( - $("
    ").addClass("nitdoc") - ) - ) - } - - $(this).nextAll(".info:first").prepend( - $("") - .addClass("nitdoc-github-editComment") - .css("cursor", "pointer") - .text((isNew ? "add" : "edit") + " comment") - .click($.proxy(GithubUI._openCommentBox, GithubUI, null, $(this))) - .after(" for ") - ) - - $(this).bind("commentbox_commit", function(event, data) { - GithubUI._saveChanges(data); - $(this).commentbox("close"); - GithubUI._reloadComments(); - }) - .bind("commentbox_preview", function(event, data) { - $("
    ") - .append($("

    ").text("Comment:")) - .append( - $("
    ") - .addClass("description") - .append( - $("
    ") - .addClass("comment") - .append( - $("
    ") - .addClass("nitdoc") - .html(marked(data.value)) - ) - ) - ) - .append($("

    ").text("Message:")) - .append( - $("
    ") - .addClass("description") - .append( - $("
    ") - .addClass("comment") - .append( - $("
    ").html(marked(data.message)) - ) - ) - ) - .modalbox({ - title: "Preview comment", - css: {"min-width": "500px"} - }) - .modalbox("open"); - }) - .bind("commentbox_open", function(event, data) { - GithubUI.openedComments++; - $(this).nextAll(".comment").hide(); - }) - .bind("commentbox_close", function(event, data) { - GithubUI.openedComments--; - $(this).nextAll(".comment").show(); - }); - }); - }, - - // reload comments from saved pull request - _reloadComments: function() { - if(!localStorage.requests){ return; } - $("p.pullRequest").remove(); - var requests = JSON.parse(localStorage.requests); - // Look for modified comments in page - for(i in requests) { - if(!requests[i]) { continue; } - var request = requests[i]; - $("textarea[data-comment-location=\"" + request.location + "\"]").each(function () { - if(request.isClosed) { - var oldComment = request.oldComment.base64Decode(); - var htmlComment = marked(oldComment); - $(this).val(oldComment); - if(!$(this).val()) { - $(this).nextAll("div.comment:first").hide(); - } else { - $(this).nextAll("div.comment:first").show(); - } - $(this).nextAll("div.comment").find("div.nitdoc").empty().html(htmlComment); - $(this).nextAll("p.info").find("a.nitdoc-github-editComment").show(); - } else { - var newComment = request.comment.base64Decode(); - var htmlComment = marked(newComment); - $(this).val(newComment); - if(!$(this).val()) { - $(this).nextAll("div.comment:first").hide(); - } else { - $(this).nextAll("div.comment:first").show(); - } - $(this).nextAll("div.comment").find("div.nitdoc").empty().html(htmlComment); - GithubUI._addPullRequestLink($(this), request); - $(this).nextAll("p.info").find("a.nitdoc-github-editComment").hide(); - } - }); - } - }, - - _addPullRequestLink: function(baseArea, request) { - baseArea.nextAll("p.info").before( - $("

    ") - .addClass("pullRequest inheritance") - .text("comment modified in ") - .append( - $("") - .attr({ - href: request.request.html_url, - title: "Review on GitHub" - }) - .text("pull request #" + request.request.number) - ) - .append(" ") - .append( - $("") - .data("pullrequest-number", request.request.number) - .addClass("nitdoc-github-update") - .text("update") - .click($.proxy(GithubUI._doUpdateRequest, GithubUI, null, baseArea, request)) - ) - .append(" ") - .append( - $("") - .data("pullrequest-number", request.request.number) - .addClass("nitdoc-github-cancel") - .text("cancel") - .click($.proxy(GithubUI._doCancelRequest, GithubUI, null, baseArea, request)) - ) - ); - }, - - /* github calls */ - - _saveChanges: function(edit) { - // if pull request update close existing pull request for the comment - if(edit.requestID) { - this._closePullRequest(edit.requestID); - } - edit.oldContent = this._getFileContent(edit.location.path); - edit.newContent = this._mergeComment(edit.oldContent, edit.newComment, edit.location); - edit.request = this._pushChanges(edit) - if(!edit.request) { - $("

    ") - .text("Unable to commit changes.
    " + response) - .modalbox({ - title: "Github commit error", - isError: true - }) - .modalbox("open"); - return; - } - this._saveRequest(edit); - }, - - // save pull request in local storage - _saveRequest: function(edit) { - var requests = {}; - if(localStorage.requests) {requests = JSON.parse(localStorage.requests)} - requests[edit.request.number] = { - request: edit.request, - location: edit.location.origin, - comment: edit.newComment.base64Encode(), - oldComment: edit.oldComment.base64Encode() - }; - localStorage.requests = JSON.stringify(requests); - }, - - /* - Creating a new pull request with the new comment take 5 steps: - 1. get the base tree from latest commit - - 2. create a new blob with updated file content - 3. post a new tree from base tree and blob - 4. post the new commit with new tree - 5. create the pull request - */ - _pushChanges: function(edit) { - var baseTree = GithubAPI.getTree(this.user, this.origin.sha); - if(!baseTree.sha) { - $("

    ") - .text("Unable to locate base tree.
    " + baseTree.status + ": " + baseTree.statusText) - .modalbox({ - title: "Github commit error", - isError: true - }) - .modalbox("open"); - return false; - } - console.log("Base tree: " + baseTree.url); - var newBlob = GithubAPI.createBlob(this.user, edit.newContent); - if(!newBlob.sha) { - $("

    ") - .text("Unable to create new blob.
    " + newBlob.status + ": " + newBlob.statusText) - .modalbox({ - title: "Github commit error", - isError: true - }) - .modalbox("open"); - return false; - } - console.log("New blob: " + newBlob.url); - var newTree = GithubAPI.createTree(this.user, baseTree, edit.location.path, newBlob); - if(!newTree.sha) { - $("

    ") - .text("Unable to create new tree.
    " + newTree.status + ": " + newTree.statusText) - .modalbox({ - title: "Github commit error", - isError: true - }) - .modalbox("open"); - return false; - } - console.log("New tree: " + newTree.url); - var newCommit = GithubAPI.createCommit(this.user, edit.message, baseTree.sha, newTree); - if(!newCommit.sha) { - $("

    ") - .text("Unable to create new commit.
    " + newCommit.status + ": " + newCommit.statusText) - .modalbox({ - title: "Github commit error", - isError: true - }) - .modalbox("open"); - return false; - } - console.log("New commit: " + newCommit.url); - var pullRequest = GithubAPI.createPullRequest(this.user, edit.title, "Pull request from Nitdoc", this.origin, newCommit.sha); - if(!pullRequest.number) { - $("

    ") - .text("Unable to create pull request.
    " + pullRequest.status + ": " + pullRequest.statusText) - .modalbox({ - title: "Github commit error", - isError: true - }) - .modalbox("open"); - return false; - } - console.log("New pull request: " + pullRequest.url); - return pullRequest; - }, - - // close previously opened pull request - _closePullRequest: function(number) { - var requests = JSON.parse(localStorage.requests); - if(!requests[number]) { - $("

    ") - .text("Unable to close pull request.
    " + "Pull request " + number + "not found") - .modalbox({ - title: "Github commit error", - isError: true - }) - .modalbox("open"); - return false; - } - // close pull request - var res = GithubAPI.updatePullRequest(this.user, "Closed from Nitdoc", "", "closed", requests[number].request); - if(!res.id) { - $("

    ") - .text("Unable to close pull request.
    " + res.status + ": " + res.statusText) - .modalbox({ - title: "Github commit error", - isError: true - }) - .modalbox("open"); - return false; - } - // update in localstorage - requests[number].isClosed = true; - localStorage.requests = JSON.stringify(requests); - }, - - /* internals */ - - _initMarked: function() { - var renderer = new marked.Renderer(); - renderer.code = function(code) { - return '

    ' + hljs.highlight('nit', code).value + '
    '; - } - renderer.codespan = function(code) { - return '' + hljs.highlight('nit', code).value + ''; - } - marked.setOptions({ - renderer: renderer, - gfm: true, - tables: true, - breaks: true, - pedantic: false, - sanitize: true, - smartLists: true, - smartypants: false - }); - }, - - _parseUpstream: function(upstream) { - var parts = upstream.split(":"); - return { - user: parts[0], - repo: parts[1], - branch: parts[2], - sha: basesha1 - }; - }, - - _getFileContent: function(githubUrl) { - var origFile = GithubAPI.getFile(this.user, githubUrl); - if(!origFile.content) { - $("

    ") - .text("Unable to locate source file.
    " + origFile.status + ": " + origFile.statusText) - .modalbox({ - title: "Github commit error", - isError: true - }) - .modalbox("open"); - return; - } - var base64Content = origFile.content.substring(0, origFile.content.length - 1) - return base64Content.base64Decode(); - }, - - _mergeComment: function(fileContent, comment, location) { - // replace comment in file content - var res = new String(); - var lines = fileContent.split("\n"); - // copy lines fron 0 to lstart - for(var i = 0; i < location.lstart - 1; i++) { - res += lines[i] + "\n"; - } - // set comment - if(comment && comment != "") { - var commentLines = comment.split("\n"); - for(var i = 0; i < commentLines.length; i++) { - var line = commentLines[i]; - var tab = location.tabpos > 1 ? "\t" : ""; - res += tab + (line.length > 0 ? "# " : "#") + line + "\n"; - } - } - // copy lines fron lend to end - for(var i = location.lend - 1; i < lines.length; i++) { - res += lines[i]; - if(i < lines.length - 1) { res += "\n"; } - } - return res; - }, - - /* events */ - - _openCommentBox: function(event, baseArea) { - baseArea.commentbox("open", this.user); - }, - - _doCancelRequest: function(event, baseArea, request) { - this._closePullRequest(request.request.number); - this._reloadComments(); - }, - - _doUpdateRequest: function(event, baseArea, request) { - baseArea.commentbox("open", this.user, request.request.number); - }, - } - - // Get github plugin data - var upstream = $("body").attr("data-github-upstream"); - var basesha1 = $("body").attr("data-github-base-sha1"); - if(upstream && basesha1) { - GithubUI.init(upstream, basesha1); - } -}); diff --git a/share/nitdoc/js/plugins/github/commentbox.js b/share/nitdoc/js/plugins/github/commentbox.js deleted file mode 100644 index 2bb6a18..0000000 --- a/share/nitdoc/js/plugins/github/commentbox.js +++ /dev/null @@ -1,231 +0,0 @@ -/* This file is part of NIT ( http://www.nitlanguage.org ). - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -/* - * CommentBox allows user to edit comments then preview, commit or cancel the changes - */ -define([ - "jquery", - "jQueryUI" -], function($) { - var Location = function(location) { - var parts = location.split(":"); - this.origin = location; - this.path = parts[0]; - this.lstart = parseInt(parts[1].split("--")[0].split(",")[0]); - this.tabpos = parseInt(parts[1].split("--")[0].split(",")[1]); - this.lend = parseInt(parts[1].split("--")[1].split(",")[0]); - this.toString = function() { - return this.path + ":" + this.lstart + "," + this.tabpos + "--" + this.lend + ",0"; - } - } - - $.widget("nitdoc.commentbox", { - - options: { - previewTxt: "preview", - commitTxt: "Commit", - cancelTxt: "Cancel", - commentboxTitle: "Edit comment", - messageTxt: "Commit message" - }, - - _create: function() { - this._id = $(".nitdoc-github-commentbox").length - this._oldComment = this.element.val(); - this._namespace = this.element.data("comment-namespace"); - this._location = new Location(this.element.data("comment-location")); - this.commentBox = $("

    ") - .hide() - .addClass("nitdoc-github-commentbox") - .append( - $("

    ") - .text(this.options.commentboxTitle) - ) - .append( - $("
    ") - .addClass("nitdoc-github-commentbox-fields") - .append( - $("
    ") - .append( - $("