all repos — hastyscribe @ 976e565e9c2ff677f2a96d6ffc7edcbcb0b9e7e3

A professional markdown compiler.

Merge pull request #96 from ZoomRmc/cssdedup

Fabio Cevasco h3rald@h3rald.com
Wed, 20 Sep 2023 15:45:36 -0400
commit

976e565e9c2ff677f2a96d6ffc7edcbcb0b9e7e3

parent

df0b0b7f7dc6bc0289e693b6600351dd6be05880

2 files changed, 52 insertions(+), 51 deletions(-)

jump to
M src/hastyscribe.nimsrc/hastyscribe.nim

@@ -10,6 +10,7 @@ tables,

httpclient, logging, critbits, + sets, ] from nimquery import querySelectorAll

@@ -261,6 +262,7 @@ else:

warn "Field '" & id & "' not defined." result = result.replace(field, "") + proc load_styles(hs: var HastyScribe) = type StyleRuleMatches = array[0..1, string]

@@ -291,7 +293,7 @@ for def in stylesheet_notes.findAll(peg_notestyle_def):

var matches: StyleRuleMatches discard def.match(peg_notestyle_def, matches) hs.noteStyles[matches[1].strip] = matches[0].strip - # Links -> already in `const.css_rules_links` + # Links -> already in `consts.css_rules_links` # Snippet Definition: # {{test -> My test snippet}}

@@ -362,33 +364,36 @@ ## the set of "hastystyles" CSS rules and prepares a custom CSS with the

## used resources. let html = document.parseHtml() var rules: seq[string] - # Check icons - for icon in html.querySelectorAll("span[class^=fa-]"): - rules.add getTableValue(hs.iconStyles, icon.attr("class"), "Icon") - # Check badges - for badge in html.querySelectorAll("span[class^=badge-]"): - rules.add getTableValue(hs.badgeStyles, badge.attr("class"), "Badge") - # Check notes - for note in html.querySelectorAll("div.tip, div.warning, div.note, div.sidebar"): - rules.add getTableValue(hs.noteStyles, note.attr("class"), "Note") - # Check links - # Init with `document-top`: it's added to the document later with `utils.add_jump_to_top_links` - var linkHrefs: CritBitTree[void] = ["#document-top"].toCritBitTree() - for link in html.querySelectorAll("a[href]"): linkHrefs.incl(link.attr("href")) - block linkStyles: - var linkRulesSet: tuple[exts, doms, protos: CritBitTree[void]] + + block icons_badges_notes: + var selSet: HashSet[string] + template fillFrom(rules: var seq[string]; t: Table[string, string]; selector, obj: string) = + for el in html.querySelectorAll(selector): selSet.incl(el.attr("class")) + for selV in selSet.items: rules.add(getTableValue(t, selV, obj)) + selSet.init() + rules.fillFrom(hs.iconStyles, "span[class^=fa-]", "Icon") # Check icons + rules.fillFrom(hs.badgeStyles, "span[class^=badge-]", "Badge") # Check badges + rules.fillFrom(hs.noteStyles, "div.tip, div.warning, div.note, div.sidebar", "Note") # Check notes + + block linkStyles: # Check links + # Init with `document-top`: it's added to the document later with `utils.add_jump_to_top_links` + var linkHrefs: CritBitTree[void] = ["#document-top"].toCritBitTree() + for link in html.querySelectorAll("a[href]"): linkHrefs.incl(link.attr("href")) + var linkRulesSets: array[CssSelPriority, CritBitTree[void]] for href in linkHrefs.keys: block search: - for (val, rule) in css_rules_links.extensions: - if href.endsWith(val): linkRulesSet.exts.incl(rule); break search - for (val, rule) in css_rules_links.domains: - if href.contains(val): linkRulesSet.doms.incl(rule); break search - for (val, rule) in css_rules_links.protocols: - if href.startsWith(val): linkRulesSet.protos.incl(rule); break search - # Adding to rules in reversed order of precedence - for rule in linkRulesSet.protos.keys: rules.add(rule) - for rule in linkRulesSet.doms.keys: rules.add(rule) - for rule in linkRulesSet.exts.keys: rules.add(rule) + for prio in countDown(csspProto, csspLowProto): # Traverse rules in order of decreasing priority + for (val, rule) in css_rules_links[prio]: + let match = + case prio: + of csspLowProto, csspProto: href.startsWith(val) + of csspDom: href.contains(val) + of csspExt: href.endsWith(val) + else: false + if match: linkRulesSets[prio].incl(rule); break search + # Adding rules in order of increasing priority + for prio in CssSelPriority: + for rule in linkRulesSets[prio]: rules.add(rule) rules.join("\n").style_tag()
M src/hastyscribepkg/consts.nimsrc/hastyscribepkg/consts.nim

@@ -2,12 +2,15 @@ import std/[pegs]

from std/strutils import strip type - Rule = tuple[selValue: string, definition: string] + CssSelPriority* = enum csspIgnore, csspLowProto, csspDom, csspExt, csspProto + Rule = tuple[selValue: string, definition: string] ## CSS selector rule Rules = seq[Rule] -proc parseLinkRules(css: string): tuple[extensions, domains, protocols: Rules] = +const CssSelLowPriorityProtos = ["http", "https"] + +proc parseLinkRules(css: string): array[CssSelPriority, Rules] = ## Parses a CSS in format adgering to `hastystyles.links.css`: - ## Each line is a link styling with a single selector of + ## Each line is a link styling with a single selector of ## `^=` / `*=` / `$=` and a `:before` # TODO: - Support multiple selectors for a styling: # either in form of "a[href$='.zip']:before, a[href$='.gz']:before"

@@ -19,14 +22,8 @@ definition <- 'a[href' op '\'' val '\']:before' \s* @ (\n / $)

op <- ['^*$'] '=' val <- [a-z0-9-.#]+ """ - type - CssSelectorKind = enum - selUnknown = "", selEnds = "$=", selContains = "*=", selStarts = "^=" - RuleAttrs = object - kind: CssSelectorKind = selUnknown - selValue: string = "" - var extensions, domains, protocols: Rules - var attrs = default(RuleAttrs) + var attr: tuple[kind: CssSelPriority; selValue: string] + var linkRules: array[CssSelPriority, Rules] let parse = peg_linkstyle_def.eventParser: pkNonTerminal: leave:

@@ -35,25 +32,24 @@ if length > 0:

case p.nt.name of "op": # debugEcho " op:", s.substr(start, start+1) - attrs.kind = case s[start]: - of '$': selEnds - of '*': selContains - of '^': selStarts - else: selUnknown - of "val": attrs.selValue = s.substr(start, start+length-1) + attr.kind = case s[start]: + of '$': csspExt # endsWiths + of '*': csspDom # contains + of '^': csspProto # startsWith + else: csspIgnore + of "val": + attr.selValue = s.substr(start, start+length-1) + if attr.kind == csspProto and attr.selValue in CssSelLowPriorityProtos: + attr.kind = csspLowProto of "definition": let definition = s.substr(start, start+length-1).strip() - if attrs.kind == selUnknown or attrs.selValue == "" or definition == "": + if attr.kind == csspIgnore or attr.selValue == "" or definition == "": echo "Error parsing `stylesheet_links`!"; quit(1) - case attrs.kind: - of selEnds: extensions.add((attrs.selValue, definition)) - of selContains: domains.add((attrs.selValue, definition)) - of selStarts: protocols.add((attrs.selValue, definition)) - else: doAssert(false) # already checked - attrs = default(RuleAttrs) + linkRules[attr.kind].add((attr.selValue, definition)) + attr = (csspLowProto, "") else: discard # parsed the file discard parse(css) - (extensions: extensions, domains: domains, protocols: protocols) + linkRules const