From 7b7bdc60ccbcda80cfb64e42bd4748fef2f504f3 Mon Sep 17 00:00:00 2001 From: whi~nyaan! Date: Sat, 11 Mar 2023 16:00:08 +0800 Subject: [PATCH] add ruff --- .shellcheckrc | 1 + bandit.yml | 6 ++ dev/raw_docs/{TODO.ymd => todo.ymd} | 13 ++- dev/scripts/py/docs.py | 5 +- dev/site/404.html | 2 +- dev/site/TODO/index.html | 1 - .../assets/javascripts/bundle.6df46069.min.js | 29 ------ .../javascripts/bundle.6df46069.min.js.map | 8 -- .../assets/javascripts/bundle.fc8c2696.min.js | 29 ++++++ .../javascripts/bundle.fc8c2696.min.js.map | 8 ++ ...db81ec45.min.js => search.208ed371.min.js} | 2 +- ....min.js.map => search.208ed371.min.js.map} | 2 +- .../assets/stylesheets/main.0d440cfe.min.css | 1 - .../stylesheets/main.0d440cfe.min.css.map | 1 - .../assets/stylesheets/main.7bf56d0a.min.css | 1 + .../stylesheets/main.7bf56d0a.min.css.map | 1 + .../stylesheets/palette.2505c338.min.css | 1 - .../stylesheets/palette.2505c338.min.css.map | 1 - .../stylesheets/palette.a0c5b2b5.min.css | 1 + .../stylesheets/palette.a0c5b2b5.min.css.map | 1 + dev/site/changelog/index.html | 2 +- dev/site/considerations/index.html | 4 +- dev/site/contributing/index.html | 4 +- dev/site/diary/index.html | 2 +- dev/site/docs/0/0/api/cli/index.html | 4 +- dev/site/docs/0/0/api/globals/index.html | 2 +- dev/site/docs/0/0/api/index.html | 2 +- dev/site/docs/0/0/api/info/index.html | 2 +- dev/site/docs/0/0/api/md_pp/index.html | 4 +- dev/site/docs/0/0/api/pdfgenerator/index.html | 4 +- .../docs/0/0/api/utils/base_cli/index.html | 8 +- .../docs/0/0/api/utils/base_exc/index.html | 4 +- dev/site/docs/0/0/api/utils/cd/index.html | 6 +- dev/site/docs/0/0/api/utils/cfg/index.html | 4 +- .../docs/0/0/api/utils/exceptions/index.html | 4 +- dev/site/docs/0/0/api/utils/index.html | 2 +- dev/site/docs/0/0/api/utils/style/index.html | 4 +- dev/site/docs/0/0/api/utils/types/index.html | 2 +- dev/site/docs/0/0/api/utils/utils/index.html | 16 ++-- dev/site/docs/0/0/contribute/index.html | 2 +- .../0/0/contribute/translations/index.html | 4 +- dev/site/docs/0/0/index.html | 2 +- dev/site/docs/0/0/installation/index.html | 4 +- dev/site/docs/0/0/markdown/index.html | 4 +- dev/site/docs/0/index.html | 2 +- dev/site/docs/index.html | 2 +- dev/site/faq/index.html | 2 +- dev/site/index.html | 2 +- dev/site/latest-bump/index.html | 2 +- dev/site/latest-commit/index.html | 2 +- dev/site/latest-release-notes/index.html | 2 +- dev/site/license/index.html | 2 +- dev/site/notes-to-self/index.html | 4 +- dev/site/search/search_index.json | 2 +- dev/site/sitemap.xml | 78 ++++++++-------- dev/site/sitemap.xml.gz | Bin 443 -> 439 bytes dev/site/terms of usage/index.html | 2 +- dev/site/todo/index.html | 1 + docs/TODO.md | 19 ---- docs/docs/0/0/api/cli.md | 2 + docs/docs/0/0/api/utils/base_cli.md | 17 ++++ docs/docs/0/0/api/utils/cd.md | 2 +- docs/docs/0/0/api/utils/exceptions.md | 1 + docs/docs/0/0/api/utils/utils.md | 30 +++++-- docs/todo.md | 26 ++++++ pyproject.toml | 65 +++++++++++++- src/cli.py | 14 ++- src/info.py | 2 +- src/md_pp.py | 6 +- src/pdfgenerator.py | 12 ++- src/utils/base_cli.py | 56 +++++++----- src/utils/base_exc.py | 16 ++-- src/utils/cd.py | 3 +- src/utils/cfg.py | 12 ++- src/utils/exceptions.py | 24 ++--- src/utils/style.py | 9 +- src/utils/utils.py | 84 +++++++++++------- 77 files changed, 439 insertions(+), 274 deletions(-) create mode 100644 .shellcheckrc create mode 100644 bandit.yml rename dev/raw_docs/{TODO.ymd => todo.ymd} (52%) delete mode 100644 dev/site/TODO/index.html delete mode 100644 dev/site/assets/javascripts/bundle.6df46069.min.js delete mode 100644 dev/site/assets/javascripts/bundle.6df46069.min.js.map create mode 100644 dev/site/assets/javascripts/bundle.fc8c2696.min.js create mode 100644 dev/site/assets/javascripts/bundle.fc8c2696.min.js.map rename dev/site/assets/javascripts/workers/{search.db81ec45.min.js => search.208ed371.min.js} (99%) rename dev/site/assets/javascripts/workers/{search.db81ec45.min.js.map => search.208ed371.min.js.map} (77%) delete mode 100644 dev/site/assets/stylesheets/main.0d440cfe.min.css delete mode 100644 dev/site/assets/stylesheets/main.0d440cfe.min.css.map create mode 100644 dev/site/assets/stylesheets/main.7bf56d0a.min.css create mode 100644 dev/site/assets/stylesheets/main.7bf56d0a.min.css.map delete mode 100644 dev/site/assets/stylesheets/palette.2505c338.min.css delete mode 100644 dev/site/assets/stylesheets/palette.2505c338.min.css.map create mode 100644 dev/site/assets/stylesheets/palette.a0c5b2b5.min.css create mode 100644 dev/site/assets/stylesheets/palette.a0c5b2b5.min.css.map create mode 100644 dev/site/todo/index.html delete mode 100644 docs/TODO.md create mode 100644 docs/todo.md diff --git a/.shellcheckrc b/.shellcheckrc new file mode 100644 index 0000000..ca2e1ce --- /dev/null +++ b/.shellcheckrc @@ -0,0 +1 @@ +disable="1087","1091","2016","2025","2045","2046","2059","2068","2086","2116","2119","2120","2148","2154","2155","2162","2164","2195","2238","3024","3043","3057","3059" \ No newline at end of file diff --git a/bandit.yml b/bandit.yml new file mode 100644 index 0000000..68eab68 --- /dev/null +++ b/bandit.yml @@ -0,0 +1,6 @@ +targets: + - "src" +skips: + - "B101" + - "B404" + - "B603" \ No newline at end of file diff --git a/dev/raw_docs/TODO.ymd b/dev/raw_docs/todo.ymd similarity index 52% rename from dev/raw_docs/TODO.ymd rename to dev/raw_docs/todo.ymd index b9ab3cd..662d46a 100644 --- a/dev/raw_docs/TODO.ymd +++ b/dev/raw_docs/todo.ymd @@ -1,10 +1,17 @@ # TODO +## Legend + +### Tags + +- **feat**: Feature + ## Todo -- [ ] n-column support -- [ ] GUI -- [ ] Custom Help Function (to only compute help page's width when help is actually called; the CLI is actually already fast enough that this might not be necessary, but is just a mere novelty) +- [ ] [docs] +- [ ] [feat] n-column support +- [ ] [feat] GUI +- [ ] [feat] Custom Help Function (to only compute help page's width when help is actually called; the CLI is actually already fast enough that this might not be necessary, but is just a mere novelty) ## In Progress diff --git a/dev/scripts/py/docs.py b/dev/scripts/py/docs.py index 792424a..1a1a71f 100755 --- a/dev/scripts/py/docs.py +++ b/dev/scripts/py/docs.py @@ -241,6 +241,9 @@ def yield_text(mod): if sm: header = [] idx_path = docs_dir(mod.name, api=True) + + print(f"Generating {idx_path}") + m, *ls = mod.name.split(".") for idx, i in enumerate(ls[::-1]): header.append(f'[{i}]({"../" * idx}{i}.md)') @@ -328,6 +331,7 @@ def main(rmv: Dict[Any, Any] = {}): for module_name, yt in yield_text(PROJECT): _dd = docs_dir(module_name, api=True) + print(f"Generating {_dd}") with open(_dd, "w") as f: f.write(yt) @@ -363,7 +367,6 @@ def main(rmv: Dict[Any, Any] = {}): ndd = {} u_ls = sorted(listdir(base), reverse=True) with open(os.path.join(docs_pdir, op_base, "README.md"), "w") as f: - print("here") f.write( H1.format("All Version") + "\n".join(f"- [Version {u}.x.x.x]({u}/README.md)" for u in u_ls) diff --git a/dev/site/404.html b/dev/site/404.html index 2fa0575..3892455 100644 --- a/dev/site/404.html +++ b/dev/site/404.html @@ -1 +1 @@ - md2pdf
\ No newline at end of file + md2pdf
\ No newline at end of file diff --git a/dev/site/TODO/index.html b/dev/site/TODO/index.html deleted file mode 100644 index 2bc06bd..0000000 --- a/dev/site/TODO/index.html +++ /dev/null @@ -1 +0,0 @@ - TODO - md2pdf
Skip to content

TODO

Todo

  • [ ] n-column support
  • [ ] GUI
  • [ ] Custom Help Function (to only compute help page's width when help is actually called; the CLI is actually already fast enough that this might not be necessary, but is just a mere novelty)

In Progress

  • [ ] Custom mermaid.js renderer (will be done after the GUI, as the HUI will be written in JS, and the rendered will be using JS too)

Done

\ No newline at end of file diff --git a/dev/site/assets/javascripts/bundle.6df46069.min.js b/dev/site/assets/javascripts/bundle.6df46069.min.js deleted file mode 100644 index 02c8d5f..0000000 --- a/dev/site/assets/javascripts/bundle.6df46069.min.js +++ /dev/null @@ -1,29 +0,0 @@ -"use strict";(()=>{var Hi=Object.create;var xr=Object.defineProperty;var Pi=Object.getOwnPropertyDescriptor;var $i=Object.getOwnPropertyNames,Ht=Object.getOwnPropertySymbols,Ii=Object.getPrototypeOf,Er=Object.prototype.hasOwnProperty,an=Object.prototype.propertyIsEnumerable;var on=(e,t,r)=>t in e?xr(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,P=(e,t)=>{for(var r in t||(t={}))Er.call(t,r)&&on(e,r,t[r]);if(Ht)for(var r of Ht(t))an.call(t,r)&&on(e,r,t[r]);return e};var sn=(e,t)=>{var r={};for(var n in e)Er.call(e,n)&&t.indexOf(n)<0&&(r[n]=e[n]);if(e!=null&&Ht)for(var n of Ht(e))t.indexOf(n)<0&&an.call(e,n)&&(r[n]=e[n]);return r};var Pt=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Fi=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of $i(t))!Er.call(e,o)&&o!==r&&xr(e,o,{get:()=>t[o],enumerable:!(n=Pi(t,o))||n.enumerable});return e};var yt=(e,t,r)=>(r=e!=null?Hi(Ii(e)):{},Fi(t||!e||!e.__esModule?xr(r,"default",{value:e,enumerable:!0}):r,e));var fn=Pt((wr,cn)=>{(function(e,t){typeof wr=="object"&&typeof cn!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(wr,function(){"use strict";function e(r){var n=!0,o=!1,i=null,a={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function s(T){return!!(T&&T!==document&&T.nodeName!=="HTML"&&T.nodeName!=="BODY"&&"classList"in T&&"contains"in T.classList)}function f(T){var Ke=T.type,De=T.tagName;return!!(De==="INPUT"&&a[Ke]&&!T.readOnly||De==="TEXTAREA"&&!T.readOnly||T.isContentEditable)}function c(T){T.classList.contains("focus-visible")||(T.classList.add("focus-visible"),T.setAttribute("data-focus-visible-added",""))}function u(T){T.hasAttribute("data-focus-visible-added")&&(T.classList.remove("focus-visible"),T.removeAttribute("data-focus-visible-added"))}function p(T){T.metaKey||T.altKey||T.ctrlKey||(s(r.activeElement)&&c(r.activeElement),n=!0)}function m(T){n=!1}function d(T){s(T.target)&&(n||f(T.target))&&c(T.target)}function h(T){s(T.target)&&(T.target.classList.contains("focus-visible")||T.target.hasAttribute("data-focus-visible-added"))&&(o=!0,window.clearTimeout(i),i=window.setTimeout(function(){o=!1},100),u(T.target))}function v(T){document.visibilityState==="hidden"&&(o&&(n=!0),B())}function B(){document.addEventListener("mousemove",z),document.addEventListener("mousedown",z),document.addEventListener("mouseup",z),document.addEventListener("pointermove",z),document.addEventListener("pointerdown",z),document.addEventListener("pointerup",z),document.addEventListener("touchmove",z),document.addEventListener("touchstart",z),document.addEventListener("touchend",z)}function ne(){document.removeEventListener("mousemove",z),document.removeEventListener("mousedown",z),document.removeEventListener("mouseup",z),document.removeEventListener("pointermove",z),document.removeEventListener("pointerdown",z),document.removeEventListener("pointerup",z),document.removeEventListener("touchmove",z),document.removeEventListener("touchstart",z),document.removeEventListener("touchend",z)}function z(T){T.target.nodeName&&T.target.nodeName.toLowerCase()==="html"||(n=!1,ne())}document.addEventListener("keydown",p,!0),document.addEventListener("mousedown",m,!0),document.addEventListener("pointerdown",m,!0),document.addEventListener("touchstart",m,!0),document.addEventListener("visibilitychange",v,!0),B(),r.addEventListener("focus",d,!0),r.addEventListener("blur",h,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var un=Pt(Sr=>{(function(e){var t=function(){try{return!!Symbol.iterator}catch(c){return!1}},r=t(),n=function(c){var u={next:function(){var p=c.shift();return{done:p===void 0,value:p}}};return r&&(u[Symbol.iterator]=function(){return u}),u},o=function(c){return encodeURIComponent(c).replace(/%20/g,"+")},i=function(c){return decodeURIComponent(String(c).replace(/\+/g," "))},a=function(){var c=function(p){Object.defineProperty(this,"_entries",{writable:!0,value:{}});var m=typeof p;if(m!=="undefined")if(m==="string")p!==""&&this._fromString(p);else if(p instanceof c){var d=this;p.forEach(function(ne,z){d.append(z,ne)})}else if(p!==null&&m==="object")if(Object.prototype.toString.call(p)==="[object Array]")for(var h=0;hd[0]?1:0}),c._entries&&(c._entries={});for(var p=0;p1?i(d[1]):"")}})})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Sr);(function(e){var t=function(){try{var o=new e.URL("b","http://a");return o.pathname="c d",o.href==="http://a/c%20d"&&o.searchParams}catch(i){return!1}},r=function(){var o=e.URL,i=function(f,c){typeof f!="string"&&(f=String(f)),c&&typeof c!="string"&&(c=String(c));var u=document,p;if(c&&(e.location===void 0||c!==e.location.href)){c=c.toLowerCase(),u=document.implementation.createHTMLDocument(""),p=u.createElement("base"),p.href=c,u.head.appendChild(p);try{if(p.href.indexOf(c)!==0)throw new Error(p.href)}catch(T){throw new Error("URL unable to set base "+c+" due to "+T)}}var m=u.createElement("a");m.href=f,p&&(u.body.appendChild(m),m.href=m.href);var d=u.createElement("input");if(d.type="url",d.value=f,m.protocol===":"||!/:/.test(m.href)||!d.checkValidity()&&!c)throw new TypeError("Invalid URL");Object.defineProperty(this,"_anchorElement",{value:m});var h=new e.URLSearchParams(this.search),v=!0,B=!0,ne=this;["append","delete","set"].forEach(function(T){var Ke=h[T];h[T]=function(){Ke.apply(h,arguments),v&&(B=!1,ne.search=h.toString(),B=!0)}}),Object.defineProperty(this,"searchParams",{value:h,enumerable:!0});var z=void 0;Object.defineProperty(this,"_updateSearchParams",{enumerable:!1,configurable:!1,writable:!1,value:function(){this.search!==z&&(z=this.search,B&&(v=!1,this.searchParams._fromString(this.search),v=!0))}})},a=i.prototype,s=function(f){Object.defineProperty(a,f,{get:function(){return this._anchorElement[f]},set:function(c){this._anchorElement[f]=c},enumerable:!0})};["hash","host","hostname","port","protocol"].forEach(function(f){s(f)}),Object.defineProperty(a,"search",{get:function(){return this._anchorElement.search},set:function(f){this._anchorElement.search=f,this._updateSearchParams()},enumerable:!0}),Object.defineProperties(a,{toString:{get:function(){var f=this;return function(){return f.href}}},href:{get:function(){return this._anchorElement.href.replace(/\?$/,"")},set:function(f){this._anchorElement.href=f,this._updateSearchParams()},enumerable:!0},pathname:{get:function(){return this._anchorElement.pathname.replace(/(^\/?)/,"/")},set:function(f){this._anchorElement.pathname=f},enumerable:!0},origin:{get:function(){var f={"http:":80,"https:":443,"ftp:":21}[this._anchorElement.protocol],c=this._anchorElement.port!=f&&this._anchorElement.port!=="";return this._anchorElement.protocol+"//"+this._anchorElement.hostname+(c?":"+this._anchorElement.port:"")},enumerable:!0},password:{get:function(){return""},set:function(f){},enumerable:!0},username:{get:function(){return""},set:function(f){},enumerable:!0}}),i.createObjectURL=function(f){return o.createObjectURL.apply(o,arguments)},i.revokeObjectURL=function(f){return o.revokeObjectURL.apply(o,arguments)},e.URL=i};if(t()||r(),e.location!==void 0&&!("origin"in e.location)){var n=function(){return e.location.protocol+"//"+e.location.hostname+(e.location.port?":"+e.location.port:"")};try{Object.defineProperty(e.location,"origin",{get:n,enumerable:!0})}catch(o){setInterval(function(){e.location.origin=n()},100)}}})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Sr)});var Qr=Pt((Lt,Kr)=>{/*! - * clipboard.js v2.0.11 - * https://clipboardjs.com/ - * - * Licensed MIT © Zeno Rocha - */(function(t,r){typeof Lt=="object"&&typeof Kr=="object"?Kr.exports=r():typeof define=="function"&&define.amd?define([],r):typeof Lt=="object"?Lt.ClipboardJS=r():t.ClipboardJS=r()})(Lt,function(){return function(){var e={686:function(n,o,i){"use strict";i.d(o,{default:function(){return ki}});var a=i(279),s=i.n(a),f=i(370),c=i.n(f),u=i(817),p=i.n(u);function m(j){try{return document.execCommand(j)}catch(O){return!1}}var d=function(O){var w=p()(O);return m("cut"),w},h=d;function v(j){var O=document.documentElement.getAttribute("dir")==="rtl",w=document.createElement("textarea");w.style.fontSize="12pt",w.style.border="0",w.style.padding="0",w.style.margin="0",w.style.position="absolute",w.style[O?"right":"left"]="-9999px";var k=window.pageYOffset||document.documentElement.scrollTop;return w.style.top="".concat(k,"px"),w.setAttribute("readonly",""),w.value=j,w}var B=function(O,w){var k=v(O);w.container.appendChild(k);var F=p()(k);return m("copy"),k.remove(),F},ne=function(O){var w=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},k="";return typeof O=="string"?k=B(O,w):O instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(O==null?void 0:O.type)?k=B(O.value,w):(k=p()(O),m("copy")),k},z=ne;function T(j){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?T=function(w){return typeof w}:T=function(w){return w&&typeof Symbol=="function"&&w.constructor===Symbol&&w!==Symbol.prototype?"symbol":typeof w},T(j)}var Ke=function(){var O=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},w=O.action,k=w===void 0?"copy":w,F=O.container,q=O.target,Le=O.text;if(k!=="copy"&&k!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(q!==void 0)if(q&&T(q)==="object"&&q.nodeType===1){if(k==="copy"&&q.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(k==="cut"&&(q.hasAttribute("readonly")||q.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(Le)return z(Le,{container:F});if(q)return k==="cut"?h(q):z(q,{container:F})},De=Ke;function Fe(j){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?Fe=function(w){return typeof w}:Fe=function(w){return w&&typeof Symbol=="function"&&w.constructor===Symbol&&w!==Symbol.prototype?"symbol":typeof w},Fe(j)}function Ti(j,O){if(!(j instanceof O))throw new TypeError("Cannot call a class as a function")}function nn(j,O){for(var w=0;w0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof F.action=="function"?F.action:this.defaultAction,this.target=typeof F.target=="function"?F.target:this.defaultTarget,this.text=typeof F.text=="function"?F.text:this.defaultText,this.container=Fe(F.container)==="object"?F.container:document.body}},{key:"listenClick",value:function(F){var q=this;this.listener=c()(F,"click",function(Le){return q.onClick(Le)})}},{key:"onClick",value:function(F){var q=F.delegateTarget||F.currentTarget,Le=this.action(q)||"copy",kt=De({action:Le,container:this.container,target:this.target(q),text:this.text(q)});this.emit(kt?"success":"error",{action:Le,text:kt,trigger:q,clearSelection:function(){q&&q.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(F){return yr("action",F)}},{key:"defaultTarget",value:function(F){var q=yr("target",F);if(q)return document.querySelector(q)}},{key:"defaultText",value:function(F){return yr("text",F)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(F){var q=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return z(F,q)}},{key:"cut",value:function(F){return h(F)}},{key:"isSupported",value:function(){var F=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],q=typeof F=="string"?[F]:F,Le=!!document.queryCommandSupported;return q.forEach(function(kt){Le=Le&&!!document.queryCommandSupported(kt)}),Le}}]),w}(s()),ki=Ri},828:function(n){var o=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function a(s,f){for(;s&&s.nodeType!==o;){if(typeof s.matches=="function"&&s.matches(f))return s;s=s.parentNode}}n.exports=a},438:function(n,o,i){var a=i(828);function s(u,p,m,d,h){var v=c.apply(this,arguments);return u.addEventListener(m,v,h),{destroy:function(){u.removeEventListener(m,v,h)}}}function f(u,p,m,d,h){return typeof u.addEventListener=="function"?s.apply(null,arguments):typeof m=="function"?s.bind(null,document).apply(null,arguments):(typeof u=="string"&&(u=document.querySelectorAll(u)),Array.prototype.map.call(u,function(v){return s(v,p,m,d,h)}))}function c(u,p,m,d){return function(h){h.delegateTarget=a(h.target,p),h.delegateTarget&&d.call(u,h)}}n.exports=f},879:function(n,o){o.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},o.nodeList=function(i){var a=Object.prototype.toString.call(i);return i!==void 0&&(a==="[object NodeList]"||a==="[object HTMLCollection]")&&"length"in i&&(i.length===0||o.node(i[0]))},o.string=function(i){return typeof i=="string"||i instanceof String},o.fn=function(i){var a=Object.prototype.toString.call(i);return a==="[object Function]"}},370:function(n,o,i){var a=i(879),s=i(438);function f(m,d,h){if(!m&&!d&&!h)throw new Error("Missing required arguments");if(!a.string(d))throw new TypeError("Second argument must be a String");if(!a.fn(h))throw new TypeError("Third argument must be a Function");if(a.node(m))return c(m,d,h);if(a.nodeList(m))return u(m,d,h);if(a.string(m))return p(m,d,h);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function c(m,d,h){return m.addEventListener(d,h),{destroy:function(){m.removeEventListener(d,h)}}}function u(m,d,h){return Array.prototype.forEach.call(m,function(v){v.addEventListener(d,h)}),{destroy:function(){Array.prototype.forEach.call(m,function(v){v.removeEventListener(d,h)})}}}function p(m,d,h){return s(document.body,m,d,h)}n.exports=f},817:function(n){function o(i){var a;if(i.nodeName==="SELECT")i.focus(),a=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var s=i.hasAttribute("readonly");s||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),s||i.removeAttribute("readonly"),a=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var f=window.getSelection(),c=document.createRange();c.selectNodeContents(i),f.removeAllRanges(),f.addRange(c),a=f.toString()}return a}n.exports=o},279:function(n){function o(){}o.prototype={on:function(i,a,s){var f=this.e||(this.e={});return(f[i]||(f[i]=[])).push({fn:a,ctx:s}),this},once:function(i,a,s){var f=this;function c(){f.off(i,c),a.apply(s,arguments)}return c._=a,this.on(i,c,s)},emit:function(i){var a=[].slice.call(arguments,1),s=((this.e||(this.e={}))[i]||[]).slice(),f=0,c=s.length;for(f;f{"use strict";/*! - * escape-html - * Copyright(c) 2012-2013 TJ Holowaychuk - * Copyright(c) 2015 Andreas Lubbe - * Copyright(c) 2015 Tiancheng "Timothy" Gu - * MIT Licensed - */var is=/["'&<>]/;Jo.exports=as;function as(e){var t=""+e,r=is.exec(t);if(!r)return t;var n,o="",i=0,a=0;for(i=r.index;i0&&i[i.length-1])&&(c[0]===6||c[0]===2)){r=0;continue}if(c[0]===3&&(!i||c[1]>i[0]&&c[1]=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function W(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var n=r.call(e),o,i=[],a;try{for(;(t===void 0||t-- >0)&&!(o=n.next()).done;)i.push(o.value)}catch(s){a={error:s}}finally{try{o&&!o.done&&(r=n.return)&&r.call(n)}finally{if(a)throw a.error}}return i}function D(e,t,r){if(r||arguments.length===2)for(var n=0,o=t.length,i;n1||s(m,d)})})}function s(m,d){try{f(n[m](d))}catch(h){p(i[0][3],h)}}function f(m){m.value instanceof Ze?Promise.resolve(m.value.v).then(c,u):p(i[0][2],m)}function c(m){s("next",m)}function u(m){s("throw",m)}function p(m,d){m(d),i.shift(),i.length&&s(i[0][0],i[0][1])}}function mn(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof xe=="function"?xe(e):e[Symbol.iterator](),r={},n("next"),n("throw"),n("return"),r[Symbol.asyncIterator]=function(){return this},r);function n(i){r[i]=e[i]&&function(a){return new Promise(function(s,f){a=e[i](a),o(s,f,a.done,a.value)})}}function o(i,a,s,f){Promise.resolve(f).then(function(c){i({value:c,done:s})},a)}}function A(e){return typeof e=="function"}function at(e){var t=function(n){Error.call(n),n.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var It=at(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: -`+r.map(function(n,o){return o+1+") "+n.toString()}).join(` - `):"",this.name="UnsubscriptionError",this.errors=r}});function Ve(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var je=function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,n,o,i;if(!this.closed){this.closed=!0;var a=this._parentage;if(a)if(this._parentage=null,Array.isArray(a))try{for(var s=xe(a),f=s.next();!f.done;f=s.next()){var c=f.value;c.remove(this)}}catch(v){t={error:v}}finally{try{f&&!f.done&&(r=s.return)&&r.call(s)}finally{if(t)throw t.error}}else a.remove(this);var u=this.initialTeardown;if(A(u))try{u()}catch(v){i=v instanceof It?v.errors:[v]}var p=this._finalizers;if(p){this._finalizers=null;try{for(var m=xe(p),d=m.next();!d.done;d=m.next()){var h=d.value;try{dn(h)}catch(v){i=i!=null?i:[],v instanceof It?i=D(D([],W(i)),W(v.errors)):i.push(v)}}}catch(v){n={error:v}}finally{try{d&&!d.done&&(o=m.return)&&o.call(m)}finally{if(n)throw n.error}}}if(i)throw new It(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)dn(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&Ve(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&Ve(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=function(){var t=new e;return t.closed=!0,t}(),e}();var Or=je.EMPTY;function Ft(e){return e instanceof je||e&&"closed"in e&&A(e.remove)&&A(e.add)&&A(e.unsubscribe)}function dn(e){A(e)?e():e.unsubscribe()}var Ae={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var st={setTimeout:function(e,t){for(var r=[],n=2;n0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var n=this,o=this,i=o.hasError,a=o.isStopped,s=o.observers;return i||a?Or:(this.currentObservers=null,s.push(r),new je(function(){n.currentObservers=null,Ve(s,r)}))},t.prototype._checkFinalizedStatuses=function(r){var n=this,o=n.hasError,i=n.thrownError,a=n.isStopped;o?r.error(i):a&&r.complete()},t.prototype.asObservable=function(){var r=new U;return r.source=this,r},t.create=function(r,n){return new wn(r,n)},t}(U);var wn=function(e){ie(t,e);function t(r,n){var o=e.call(this)||this;return o.destination=r,o.source=n,o}return t.prototype.next=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.next)===null||o===void 0||o.call(n,r)},t.prototype.error=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.error)===null||o===void 0||o.call(n,r)},t.prototype.complete=function(){var r,n;(n=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||n===void 0||n.call(r)},t.prototype._subscribe=function(r){var n,o;return(o=(n=this.source)===null||n===void 0?void 0:n.subscribe(r))!==null&&o!==void 0?o:Or},t}(E);var Et={now:function(){return(Et.delegate||Date).now()},delegate:void 0};var wt=function(e){ie(t,e);function t(r,n,o){r===void 0&&(r=1/0),n===void 0&&(n=1/0),o===void 0&&(o=Et);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=n,i._timestampProvider=o,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=n===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,n),i}return t.prototype.next=function(r){var n=this,o=n.isStopped,i=n._buffer,a=n._infiniteTimeWindow,s=n._timestampProvider,f=n._windowTime;o||(i.push(r),!a&&i.push(s.now()+f)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var n=this._innerSubscribe(r),o=this,i=o._infiniteTimeWindow,a=o._buffer,s=a.slice(),f=0;f0?e.prototype.requestAsyncId.call(this,r,n,o):(r.actions.push(this),r._scheduled||(r._scheduled=ut.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,n,o){var i;if(o===void 0&&(o=0),o!=null?o>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,n,o);var a=r.actions;n!=null&&((i=a[a.length-1])===null||i===void 0?void 0:i.id)!==n&&(ut.cancelAnimationFrame(n),r._scheduled=void 0)},t}(Wt);var On=function(e){ie(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var n=this._scheduled;this._scheduled=void 0;var o=this.actions,i;r=r||o.shift();do if(i=r.execute(r.state,r.delay))break;while((r=o[0])&&r.id===n&&o.shift());if(this._active=!1,i){for(;(r=o[0])&&r.id===n&&o.shift();)r.unsubscribe();throw i}},t}(Dt);var we=new On(Tn);var R=new U(function(e){return e.complete()});function Vt(e){return e&&A(e.schedule)}function kr(e){return e[e.length-1]}function Qe(e){return A(kr(e))?e.pop():void 0}function Se(e){return Vt(kr(e))?e.pop():void 0}function zt(e,t){return typeof kr(e)=="number"?e.pop():t}var pt=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function Nt(e){return A(e==null?void 0:e.then)}function qt(e){return A(e[ft])}function Kt(e){return Symbol.asyncIterator&&A(e==null?void 0:e[Symbol.asyncIterator])}function Qt(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function Ki(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var Yt=Ki();function Gt(e){return A(e==null?void 0:e[Yt])}function Bt(e){return ln(this,arguments,function(){var r,n,o,i;return $t(this,function(a){switch(a.label){case 0:r=e.getReader(),a.label=1;case 1:a.trys.push([1,,9,10]),a.label=2;case 2:return[4,Ze(r.read())];case 3:return n=a.sent(),o=n.value,i=n.done,i?[4,Ze(void 0)]:[3,5];case 4:return[2,a.sent()];case 5:return[4,Ze(o)];case 6:return[4,a.sent()];case 7:return a.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function Jt(e){return A(e==null?void 0:e.getReader)}function $(e){if(e instanceof U)return e;if(e!=null){if(qt(e))return Qi(e);if(pt(e))return Yi(e);if(Nt(e))return Gi(e);if(Kt(e))return _n(e);if(Gt(e))return Bi(e);if(Jt(e))return Ji(e)}throw Qt(e)}function Qi(e){return new U(function(t){var r=e[ft]();if(A(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function Yi(e){return new U(function(t){for(var r=0;r=2;return function(n){return n.pipe(e?_(function(o,i){return e(o,i,n)}):de,Oe(1),r?Pe(t):zn(function(){return new Zt}))}}function Nn(){for(var e=[],t=0;t=2,!0))}function ue(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new E}:t,n=e.resetOnError,o=n===void 0?!0:n,i=e.resetOnComplete,a=i===void 0?!0:i,s=e.resetOnRefCountZero,f=s===void 0?!0:s;return function(c){var u,p,m,d=0,h=!1,v=!1,B=function(){p==null||p.unsubscribe(),p=void 0},ne=function(){B(),u=m=void 0,h=v=!1},z=function(){var T=u;ne(),T==null||T.unsubscribe()};return g(function(T,Ke){d++,!v&&!h&&B();var De=m=m!=null?m:r();Ke.add(function(){d--,d===0&&!v&&!h&&(p=jr(z,f))}),De.subscribe(Ke),!u&&d>0&&(u=new tt({next:function(Fe){return De.next(Fe)},error:function(Fe){v=!0,B(),p=jr(ne,o,Fe),De.error(Fe)},complete:function(){h=!0,B(),p=jr(ne,a),De.complete()}}),$(T).subscribe(u))})(c)}}function jr(e,t){for(var r=[],n=2;ne.next(document)),e}function K(e,t=document){return Array.from(t.querySelectorAll(e))}function V(e,t=document){let r=ce(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function ce(e,t=document){return t.querySelector(e)||void 0}function _e(){return document.activeElement instanceof HTMLElement&&document.activeElement||void 0}function rr(e){return L(b(document.body,"focusin"),b(document.body,"focusout")).pipe(He(1),l(()=>{let t=_e();return typeof t!="undefined"?e.contains(t):!1}),N(e===_e()),G())}function Je(e){return{x:e.offsetLeft,y:e.offsetTop}}function Yn(e){return L(b(window,"load"),b(window,"resize")).pipe(Re(0,we),l(()=>Je(e)),N(Je(e)))}function nr(e){return{x:e.scrollLeft,y:e.scrollTop}}function dt(e){return L(b(e,"scroll"),b(window,"resize")).pipe(Re(0,we),l(()=>nr(e)),N(nr(e)))}var Bn=function(){if(typeof Map!="undefined")return Map;function e(t,r){var n=-1;return t.some(function(o,i){return o[0]===r?(n=i,!0):!1}),n}return function(){function t(){this.__entries__=[]}return Object.defineProperty(t.prototype,"size",{get:function(){return this.__entries__.length},enumerable:!0,configurable:!0}),t.prototype.get=function(r){var n=e(this.__entries__,r),o=this.__entries__[n];return o&&o[1]},t.prototype.set=function(r,n){var o=e(this.__entries__,r);~o?this.__entries__[o][1]=n:this.__entries__.push([r,n])},t.prototype.delete=function(r){var n=this.__entries__,o=e(n,r);~o&&n.splice(o,1)},t.prototype.has=function(r){return!!~e(this.__entries__,r)},t.prototype.clear=function(){this.__entries__.splice(0)},t.prototype.forEach=function(r,n){n===void 0&&(n=null);for(var o=0,i=this.__entries__;o0},e.prototype.connect_=function(){!zr||this.connected_||(document.addEventListener("transitionend",this.onTransitionEnd_),window.addEventListener("resize",this.refresh),xa?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener("DOMSubtreeModified",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},e.prototype.disconnect_=function(){!zr||!this.connected_||(document.removeEventListener("transitionend",this.onTransitionEnd_),window.removeEventListener("resize",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener("DOMSubtreeModified",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},e.prototype.onTransitionEnd_=function(t){var r=t.propertyName,n=r===void 0?"":r,o=ya.some(function(i){return!!~n.indexOf(i)});o&&this.refresh()},e.getInstance=function(){return this.instance_||(this.instance_=new e),this.instance_},e.instance_=null,e}(),Jn=function(e,t){for(var r=0,n=Object.keys(t);r0},e}(),Zn=typeof WeakMap!="undefined"?new WeakMap:new Bn,eo=function(){function e(t){if(!(this instanceof e))throw new TypeError("Cannot call a class as a function.");if(!arguments.length)throw new TypeError("1 argument required, but only 0 present.");var r=Ea.getInstance(),n=new Ra(t,r,this);Zn.set(this,n)}return e}();["observe","unobserve","disconnect"].forEach(function(e){eo.prototype[e]=function(){var t;return(t=Zn.get(this))[e].apply(t,arguments)}});var ka=function(){return typeof or.ResizeObserver!="undefined"?or.ResizeObserver:eo}(),to=ka;var ro=new E,Ha=I(()=>H(new to(e=>{for(let t of e)ro.next(t)}))).pipe(x(e=>L(Te,H(e)).pipe(C(()=>e.disconnect()))),J(1));function he(e){return{width:e.offsetWidth,height:e.offsetHeight}}function ge(e){return Ha.pipe(S(t=>t.observe(e)),x(t=>ro.pipe(_(({target:r})=>r===e),C(()=>t.unobserve(e)),l(()=>he(e)))),N(he(e)))}function bt(e){return{width:e.scrollWidth,height:e.scrollHeight}}function sr(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}var no=new E,Pa=I(()=>H(new IntersectionObserver(e=>{for(let t of e)no.next(t)},{threshold:0}))).pipe(x(e=>L(Te,H(e)).pipe(C(()=>e.disconnect()))),J(1));function cr(e){return Pa.pipe(S(t=>t.observe(e)),x(t=>no.pipe(_(({target:r})=>r===e),C(()=>t.unobserve(e)),l(({isIntersecting:r})=>r))))}function oo(e,t=16){return dt(e).pipe(l(({y:r})=>{let n=he(e),o=bt(e);return r>=o.height-n.height-t}),G())}var fr={drawer:V("[data-md-toggle=drawer]"),search:V("[data-md-toggle=search]")};function io(e){return fr[e].checked}function qe(e,t){fr[e].checked!==t&&fr[e].click()}function Ue(e){let t=fr[e];return b(t,"change").pipe(l(()=>t.checked),N(t.checked))}function $a(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function Ia(){return L(b(window,"compositionstart").pipe(l(()=>!0)),b(window,"compositionend").pipe(l(()=>!1))).pipe(N(!1))}function ao(){let e=b(window,"keydown").pipe(_(t=>!(t.metaKey||t.ctrlKey)),l(t=>({mode:io("search")?"search":"global",type:t.key,claim(){t.preventDefault(),t.stopPropagation()}})),_(({mode:t,type:r})=>{if(t==="global"){let n=_e();if(typeof n!="undefined")return!$a(n,r)}return!0}),ue());return Ia().pipe(x(t=>t?R:e))}function Me(){return new URL(location.href)}function ot(e){location.href=e.href}function so(){return new E}function co(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)co(e,r)}function M(e,t,...r){let n=document.createElement(e);if(t)for(let o of Object.keys(t))typeof t[o]!="undefined"&&(typeof t[o]!="boolean"?n.setAttribute(o,t[o]):n.setAttribute(o,""));for(let o of r)co(n,o);return n}function ur(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function fo(){return location.hash.substring(1)}function uo(e){let t=M("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function Fa(){return b(window,"hashchange").pipe(l(fo),N(fo()),_(e=>e.length>0),J(1))}function po(){return Fa().pipe(l(e=>ce(`[id="${e}"]`)),_(e=>typeof e!="undefined"))}function Nr(e){let t=matchMedia(e);return er(r=>t.addListener(()=>r(t.matches))).pipe(N(t.matches))}function lo(){let e=matchMedia("print");return L(b(window,"beforeprint").pipe(l(()=>!0)),b(window,"afterprint").pipe(l(()=>!1))).pipe(N(e.matches))}function qr(e,t){return e.pipe(x(r=>r?t():R))}function pr(e,t={credentials:"same-origin"}){return pe(fetch(`${e}`,t)).pipe(fe(()=>R),x(r=>r.status!==200?Tt(()=>new Error(r.statusText)):H(r)))}function We(e,t){return pr(e,t).pipe(x(r=>r.json()),J(1))}function mo(e,t){let r=new DOMParser;return pr(e,t).pipe(x(n=>n.text()),l(n=>r.parseFromString(n,"text/xml")),J(1))}function lr(e){let t=M("script",{src:e});return I(()=>(document.head.appendChild(t),L(b(t,"load"),b(t,"error").pipe(x(()=>Tt(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(l(()=>{}),C(()=>document.head.removeChild(t)),Oe(1))))}function ho(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function bo(){return L(b(window,"scroll",{passive:!0}),b(window,"resize",{passive:!0})).pipe(l(ho),N(ho()))}function vo(){return{width:innerWidth,height:innerHeight}}function go(){return b(window,"resize",{passive:!0}).pipe(l(vo),N(vo()))}function yo(){return Q([bo(),go()]).pipe(l(([e,t])=>({offset:e,size:t})),J(1))}function mr(e,{viewport$:t,header$:r}){let n=t.pipe(X("size")),o=Q([n,r]).pipe(l(()=>Je(e)));return Q([r,t,o]).pipe(l(([{height:i},{offset:a,size:s},{x:f,y:c}])=>({offset:{x:a.x-f,y:a.y-c+i},size:s})))}(()=>{function e(n,o){parent.postMessage(n,o||"*")}function t(...n){return n.reduce((o,i)=>o.then(()=>new Promise(a=>{let s=document.createElement("script");s.src=i,s.onload=a,document.body.appendChild(s)})),Promise.resolve())}var r=class{constructor(n){this.url=n,this.onerror=null,this.onmessage=null,this.onmessageerror=null,this.m=a=>{a.source===this.w&&(a.stopImmediatePropagation(),this.dispatchEvent(new MessageEvent("message",{data:a.data})),this.onmessage&&this.onmessage(a))},this.e=(a,s,f,c,u)=>{if(s===this.url.toString()){let p=new ErrorEvent("error",{message:a,filename:s,lineno:f,colno:c,error:u});this.dispatchEvent(p),this.onerror&&this.onerror(p)}};let o=new EventTarget;this.addEventListener=o.addEventListener.bind(o),this.removeEventListener=o.removeEventListener.bind(o),this.dispatchEvent=o.dispatchEvent.bind(o);let i=document.createElement("iframe");i.width=i.height=i.frameBorder="0",document.body.appendChild(this.iframe=i),this.w.document.open(),this.w.document.write(`
\ No newline at end of file + Changelog - md2pdf
\ No newline at end of file diff --git a/dev/site/considerations/index.html b/dev/site/considerations/index.html index 655635e..28df2d0 100644 --- a/dev/site/considerations/index.html +++ b/dev/site/considerations/index.html @@ -1,4 +1,4 @@ - Considerations - md2pdf

Considerations for Future Feature Implementation

Page Breaks

There is no plain markdown way to add pagebreak in a markdown file. However, I came across this stackoverflow answer that mentions that the answer-er uses <<<<>>>> to denote pagebreak in their documents. And I liked that! And as such, I think I will implement just that in later versions of this program.

Columns

Before this project can even convert markdown to PDF files in sub-ten seconds, I have been using tables as substitute for columns. This is as the Commonmark Markdown specification does not support such feature.

However, there is a simple problem with tables in markdown: it does not support multi-line cells

Time and time again, I have searched for ways to be able to write multi-line cells in a kind of markdown way. All of them are ugly implementations. None of them can satisfy me.

And then I came across MultiMarkdown's table documentation which makes an interesting observation:

If you need complex tables you will need to create them by hand or with a tool specifically designed for your output format. At some point, however, you should consider whether a table is really the best approach if you find MultiMarkdown tables too limiting.

And I think that that is true.

However, I have thought of a solution. That is to parse markdown inside HTML tags. Such as that the following markdown...

<table>
+ Considerations - md2pdf        
         
       

Considerations for Future Feature Implementation

Page Breaks

There is no plain markdown way to add pagebreak in a markdown file. However, I came across this stackoverflow answer that mentions that the answer-er uses <<<<>>>> to denote pagebreak in their documents. And I liked that! And as such, I think I will implement just that in later versions of this program.

Columns

Before this project can even convert markdown to PDF files in sub-ten seconds, I have been using tables as substitute for columns. This is as the Commonmark Markdown specification does not support such feature.

However, there is a simple problem with tables in markdown: it does not support multi-line cells

Time and time again, I have searched for ways to be able to write multi-line cells in a kind of markdown way. All of them are ugly implementations. None of them can satisfy me.

And then I came across MultiMarkdown's table documentation which makes an interesting observation:

If you need complex tables you will need to create them by hand or with a tool specifically designed for your output format. At some point, however, you should consider whether a table is really the best approach if you find MultiMarkdown tables too limiting.

And I think that that is true.

However, I have thought of a solution. That is to parse markdown inside HTML tags. Such as that the following markdown...

<table>
     <tr>
         <th>Header</th>
     </tr>
@@ -107,4 +107,4 @@
                 B --) C: tx res
             end
         end
-    end
\ No newline at end of file + end
\ No newline at end of file diff --git a/dev/site/contributing/index.html b/dev/site/contributing/index.html index 7a7e03d..c2c0517 100644 --- a/dev/site/contributing/index.html +++ b/dev/site/contributing/index.html @@ -1,8 +1,8 @@ - Contributing - md2pdf

Contributing to md2pdf

First off, thanks for taking the time to contribute! ❤️

All types of contributions are encouraged and valued. See the Table of Contents for different ways to help and details about how this project handles them. Please make sure to read the relevant section before making your contribution. It will make it a lot easier for us maintainers and smooth out the experience for all involved. The community looks forward to your contributions. 🎉

And if you like the project, but just don't have time to contribute, that's fine. There are other easy ways to support the project and show your appreciation, which we would also be very happy about: - Star the project - Tweet about it - Refer this project in your project's README - Mention the project at local meetups and tell your friends/colleagues

Code of Conduct

This project and everyone participating in it is governed by the md2pdf Code of Conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to <>.

I Have a Question

If you want to ask a question, we assume that you have read the available Latest Documentation (0.0.x.x).

Before you ask a question, it is best to search for existing Issues that might help you. In case you have found a suitable issue and still need clarification, you can write your question in this issue. It is also advisable to search the internet for answers first.

If you then still feel the need to ask a question and need clarification, we recommend the following:

  • Open an Issue.
  • Provide as much context as you can about what you're running into.
  • Provide the following information:
    • OS name and version If in Linux, include linux distribution and kernel version; and
    • Python version

We will then take care of the issue as soon as possible.

I Want To Contribute

When contributing to this project, you must agree that you have authored 100% of the content, that you have the necessary rights to the content and that the content you contribute may be provided under the project license.

Reporting Bugs

Before Submitting a Bug Report

A good bug report shouldn't leave others needing to chase you up for more information. Therefore, we ask you to investigate carefully, collect information and describe the issue in detail in your report. Please complete the following steps in advance to help us fix any potential bug as fast as possible.

  • Make sure that you are using the latest version.
  • Determine if your bug is really a bug and not an error on your side e.g. using incompatible environment components/versions (Make sure that you have read the Latest Documentation (0.0.x.x). If you are looking for support, you might want to check this section).
  • To see if other users have experienced (and potentially already solved) the same issue you are having, check if there is not already a bug report existing for your bug or error in the bug tracker.
  • Also make sure to search the internet (including Stack Overflow) to see if users outside of the GitHub community have discussed the issue.

  • Collect information about the bug

  • Stack trace (Traceback)
  • OS, Platform and Version (Windows, Linux, macOS, x86, ARM)
  • Version of the interpreter, compiler, SDK, runtime environment, package manager, depending on what seems relevant.
  • Possibly your input and the output
  • Can you reliably reproduce the issue? And can you also reproduce it with older versions?

How Do I Submit a Good Bug Report?

You must never report security related issues, vulnerabilities or bugs including sensitive information to the issue tracker, or elsewhere in public. Instead sensitive bugs must be sent by email to <>.

We use GitHub issues to track bugs and errors. If you run into an issue with the project:

  • Open an Issue. (Since we can't be sure at this point whether it is a bug or not, we ask you not to talk about a bug yet and not to label the issue.)
  • Explain the behavior you would expect and the actual behavior.
  • Please provide as much context as possible and describe the reproduction steps that someone else can follow to recreate the issue on their own. This usually includes your code. For good bug reports you should isolate the problem and create a reduced test case.
  • Provide the information you collected in the previous section.

Once it's filed:

  • The project team will label the issue accordingly.
  • A team member will try to reproduce the issue with your provided steps. If there are no reproduction steps or no obvious way to reproduce the issue, the team will ask you for those steps and mark the issue as needs-repro. Bugs with the needs-repro tag will not be addressed until they are reproduced.
  • If the team is able to reproduce the issue, it will be marked needs-fix, as well as possibly other tags (such as critical), and the issue will be left to be implemented by someone.

Suggesting Enhancements

This section guides you through submitting an enhancement suggestion for md2pdf, including completely new features and minor improvements to existing functionality. Following these guidelines will help maintainers and the community to understand your suggestion and find related suggestions.

Before Submitting an Enhancement

  • Make sure that you are using the latest version.
  • Read the Latest Documentation (0.0.x.x) carefully and find out if the functionality is already covered, maybe by an individual configuration.
  • Perform a search to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one.
  • Find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the project's developers of the merits of this feature. Keep in mind that we want features that will be useful to the majority of our users and not just a small subset. If you're just targeting a minority of users, consider writing an add-on/plugin library.

How Do I Submit a Good Enhancement Suggestion?

Enhancement suggestions are tracked as GitHub issues.

  • Use a clear and descriptive title for the issue to identify the suggestion.
  • Provide a step-by-step description of the suggested enhancement in as many details as possible.
  • Describe the current behavior and explain which behavior you expected to see instead and why. At this point you can also tell which alternatives do not work for you.
  • You may want to include screenshots and animated GIFs which help you demonstrate the steps or point out the part which the suggestion is related to. You can use this tool to record GIFs on macOS and Windows, and this tool or this tool on Linux.
  • Explain why this enhancement would be useful to most md2pdf users. You may also want to point out the other projects that solved it better and which could serve as inspiration.
GitHub

Contributing to md2pdf

First off, thanks for taking the time to contribute! ❤️

All types of contributions are encouraged and valued. See the Table of Contents for different ways to help and details about how this project handles them. Please make sure to read the relevant section before making your contribution. It will make it a lot easier for us maintainers and smooth out the experience for all involved. The community looks forward to your contributions. 🎉

And if you like the project, but just don't have time to contribute, that's fine. There are other easy ways to support the project and show your appreciation, which we would also be very happy about: - Star the project - Tweet about it - Refer this project in your project's README - Mention the project at local meetups and tell your friends/colleagues

Code of Conduct

This project and everyone participating in it is governed by the md2pdf Code of Conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to <>.

I Have a Question

If you want to ask a question, we assume that you have read the available Latest Documentation (0.0.x.x).

Before you ask a question, it is best to search for existing Issues that might help you. In case you have found a suitable issue and still need clarification, you can write your question in this issue. It is also advisable to search the internet for answers first.

If you then still feel the need to ask a question and need clarification, we recommend the following:

  • Open an Issue.
  • Provide as much context as you can about what you're running into.
  • Provide the following information:
    • OS name and version If in Linux, include linux distribution and kernel version; and
    • Python version

We will then take care of the issue as soon as possible.

I Want To Contribute

When contributing to this project, you must agree that you have authored 100% of the content, that you have the necessary rights to the content and that the content you contribute may be provided under the project license.

Reporting Bugs

Before Submitting a Bug Report

A good bug report shouldn't leave others needing to chase you up for more information. Therefore, we ask you to investigate carefully, collect information and describe the issue in detail in your report. Please complete the following steps in advance to help us fix any potential bug as fast as possible.

  • Make sure that you are using the latest version.
  • Determine if your bug is really a bug and not an error on your side e.g. using incompatible environment components/versions (Make sure that you have read the Latest Documentation (0.0.x.x). If you are looking for support, you might want to check this section).
  • To see if other users have experienced (and potentially already solved) the same issue you are having, check if there is not already a bug report existing for your bug or error in the bug tracker.
  • Also make sure to search the internet (including Stack Overflow) to see if users outside of the GitHub community have discussed the issue.

  • Collect information about the bug

  • Stack trace (Traceback)
  • OS, Platform and Version (Windows, Linux, macOS, x86, ARM)
  • Version of the interpreter, compiler, SDK, runtime environment, package manager, depending on what seems relevant.
  • Possibly your input and the output
  • Can you reliably reproduce the issue? And can you also reproduce it with older versions?

How Do I Submit a Good Bug Report?

You must never report security related issues, vulnerabilities or bugs including sensitive information to the issue tracker, or elsewhere in public. Instead sensitive bugs must be sent by email to <>.

We use GitHub issues to track bugs and errors. If you run into an issue with the project:

  • Open an Issue. (Since we can't be sure at this point whether it is a bug or not, we ask you not to talk about a bug yet and not to label the issue.)
  • Explain the behavior you would expect and the actual behavior.
  • Please provide as much context as possible and describe the reproduction steps that someone else can follow to recreate the issue on their own. This usually includes your code. For good bug reports you should isolate the problem and create a reduced test case.
  • Provide the information you collected in the previous section.

Once it's filed:

  • The project team will label the issue accordingly.
  • A team member will try to reproduce the issue with your provided steps. If there are no reproduction steps or no obvious way to reproduce the issue, the team will ask you for those steps and mark the issue as needs-repro. Bugs with the needs-repro tag will not be addressed until they are reproduced.
  • If the team is able to reproduce the issue, it will be marked needs-fix, as well as possibly other tags (such as critical), and the issue will be left to be implemented by someone.

Suggesting Enhancements

This section guides you through submitting an enhancement suggestion for md2pdf, including completely new features and minor improvements to existing functionality. Following these guidelines will help maintainers and the community to understand your suggestion and find related suggestions.

Before Submitting an Enhancement

  • Make sure that you are using the latest version.
  • Read the Latest Documentation (0.0.x.x) carefully and find out if the functionality is already covered, maybe by an individual configuration.
  • Perform a search to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one.
  • Find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the project's developers of the merits of this feature. Keep in mind that we want features that will be useful to the majority of our users and not just a small subset. If you're just targeting a minority of users, consider writing an add-on/plugin library.

How Do I Submit a Good Enhancement Suggestion?

Enhancement suggestions are tracked as GitHub issues.

  • Use a clear and descriptive title for the issue to identify the suggestion.
  • Provide a step-by-step description of the suggested enhancement in as many details as possible.
  • Describe the current behavior and explain which behavior you expected to see instead and why. At this point you can also tell which alternatives do not work for you.
  • You may want to include screenshots and animated GIFs which help you demonstrate the steps or point out the part which the suggestion is related to. You can use this tool to record GIFs on macOS and Windows, and this tool or this tool on Linux.
  • Explain why this enhancement would be useful to most md2pdf users. You may also want to point out the other projects that solved it better and which could serve as inspiration.

Your First Code Contribution

Improving The Documentation

Submitting a Pull Request

This is based on Michael Herrmann's gist titled Good PRs are minimal.

Every Pull Request (hereinafter referred to as PR) should have one, and only one, unique goal. The PR should make the absolute minimum number of changes that are required to achieve this goal.

The fewer things you change, the easier it will be for the team to see what you did, and thus gain confidence that you PR makes sense.

Dont’s

  • Changing whitespace unnecessarily, eg. switching tabs and spaces.

    This leads to huge numbers of unnecessarily changed lines of code.

  • Running a linter not listed in the linters currently used by the project

  • Don't unnecessarily introduce new tools or dependencies. I'm sure you have your favorites. But don't force them on me or other contributors. Stick to those that are absolutely required, or come with the language.
  • Obey the same code style as the library: Tabs or spaces, maximum line length, etc.

In short: Good PRs are minimal. You're very welcome to add several improvements. But please make them in separate PRs.

Style guides

Commit Messages

This repository does not enforce a style guide on commits. However, it is highly recommended to be concise and informative when writing commit messages.

Code

This project uses the following linters for the

Join The Project Team

Attribution

This guide is based on the contributing-gen. Make your own!

\ No newline at end of file +-->

Submitting a Pull Request

This is based on Michael Herrmann's gist titled Good PRs are minimal.

Every Pull Request (hereinafter referred to as PR) should have one, and only one, unique goal. The PR should make the absolute minimum number of changes that are required to achieve this goal.

The fewer things you change, the easier it will be for the team to see what you did, and thus gain confidence that you PR makes sense.

Dont’s

  • Changing whitespace unnecessarily, eg. switching tabs and spaces.

    This leads to huge numbers of unnecessarily changed lines of code.

  • Running a linter not listed in the linters currently used by the project

  • Don't unnecessarily introduce new tools or dependencies. I'm sure you have your favorites. But don't force them on me or other contributors. Stick to those that are absolutely required, or come with the language.
  • Obey the same code style as the library: Tabs or spaces, maximum line length, etc.

In short: Good PRs are minimal. You're very welcome to add several improvements. But please make them in separate PRs.

Style guides

Commit Messages

This repository does not enforce a style guide on commits. However, it is highly recommended to be concise and informative when writing commit messages.

Code

This project uses the following linters for the

Join The Project Team

Attribution

This guide is based on the contributing-gen. Make your own!

\ No newline at end of file diff --git a/dev/site/diary/index.html b/dev/site/diary/index.html index 64938ca..be1b3fd 100644 --- a/dev/site/diary/index.html +++ b/dev/site/diary/index.html @@ -1 +1 @@ - Diary - md2pdf

r/offmychest

Written below are rants and lessons I have learned in making this project, and whatnot. Basically, I do not know, I just want to get it out of my chest.

KaTeX Support

For this project, I planned it to ship with a KaTeX support.

I have only found a single python-markdown extension that is also compatible with Weasyprint, and that is markdown-katex by mbarkhau. However, it is so dang slow.

From my testing, it takes about 200 seconds (or roughly over 3 mins) to convert a markdown file with around 5-10 formulae in it to a 200 kb PDF file, which is about a kbps. However, that is a shitty metric, as there is an image in there, but you get the point, It is slow as fuck.

Now, what I did is attempt to rewrite mbarkhau's implementation of KaTeX for python-markdown. Built it from the ground up, taking motivation from the original project and some other extensions along the way. Heavily rebuilding the logic behind the things that I figured out takes up most of the time.

I narrowed it down to two things that slows it down the most: the preprocessor and postprocessor functions. I figured out that the iterator for feeding KaTeX formulae into the KaTeX binary took the longest as the process persists for quite a while on my machine's process monitoring tool. And as such, I made that process multithreaded.

Weeks after almost achieving feature-parity with the original project, I encountered an error. It was not of my program, but of the python-markdown's. And as such, I dug up the code that caused that error and extracted that to my program to be able to modify the code and remove the snippet that causes the error in the first place. And of course, that affected the rendering process.

There's no more hope. I did something wrong, and I can not track down where it went wrong.

Then, it finally hit me. The problem is when I attempted to rebuild the already perfect python-markdown KaTeX implementation. I just need to make it multithreaded. And while I still need to extract the stuff to make it work with the other stuff that I plan to add, I still only need to modify about 20% of the original project. I am so fucking dumb.

Or so I thought, two weeks later, after doing just that, it's still slow. And what I mean by slow is that I can run the program, wash the plate I used for eating the leftover cake for like about a minute or two, make myself a cup of coffee, and come back to that damn thing still running! Luckily, I narrowed it down to the very root cause of it all: the logic that searches for the KaTeX binary in the machine.

I do not know how or why the heck is it so slow. In any case, I replaced it with a shutil's implementation of which, modified to work with the extension. And fortunately, it worked! The logic still looks the same as the old one, but the damn thing runs from 30 secs down to sub-five seconds, depending where the binary is at. Like, whaaaaaat?!?!

What is the moral of the story then? That someone's code might actually be the best solution for the problem. But if it does not work, then do not try to rebuild it from the ground up. See first if you can modify some parts of it to work with your problem. Then if it does not work, then proceed to rebuilding it. As often times, that solution might be the best solution for that exact problem, but not for your own, exact problem.

Or is that it?

Maybe I just wanted to rant about the stupid weeks I have wasted for this little thing to fucking work? Or is it because I just wanted to flex how much I have optimized a single thing?

I do not fucking know, but I sure did flex'd to my friends about how I "optimized" a program to run 40x faster. I mean, where is the lie?

Now, where am I again? Oh, right, KaTeX support. Yay, finally added! UwU

\ No newline at end of file + Diary - md2pdf

r/offmychest

Written below are rants and lessons I have learned in making this project, and whatnot. Basically, I do not know, I just want to get it out of my chest.

KaTeX Support

For this project, I planned it to ship with a KaTeX support.

I have only found a single python-markdown extension that is also compatible with Weasyprint, and that is markdown-katex by mbarkhau. However, it is so dang slow.

From my testing, it takes about 200 seconds (or roughly over 3 mins) to convert a markdown file with around 5-10 formulae in it to a 200 kb PDF file, which is about a kbps. However, that is a shitty metric, as there is an image in there, but you get the point, It is slow as fuck.

Now, what I did is attempt to rewrite mbarkhau's implementation of KaTeX for python-markdown. Built it from the ground up, taking motivation from the original project and some other extensions along the way. Heavily rebuilding the logic behind the things that I figured out takes up most of the time.

I narrowed it down to two things that slows it down the most: the preprocessor and postprocessor functions. I figured out that the iterator for feeding KaTeX formulae into the KaTeX binary took the longest as the process persists for quite a while on my machine's process monitoring tool. And as such, I made that process multithreaded.

Weeks after almost achieving feature-parity with the original project, I encountered an error. It was not of my program, but of the python-markdown's. And as such, I dug up the code that caused that error and extracted that to my program to be able to modify the code and remove the snippet that causes the error in the first place. And of course, that affected the rendering process.

There's no more hope. I did something wrong, and I can not track down where it went wrong.

Then, it finally hit me. The problem is when I attempted to rebuild the already perfect python-markdown KaTeX implementation. I just need to make it multithreaded. And while I still need to extract the stuff to make it work with the other stuff that I plan to add, I still only need to modify about 20% of the original project. I am so fucking dumb.

Or so I thought, two weeks later, after doing just that, it's still slow. And what I mean by slow is that I can run the program, wash the plate I used for eating the leftover cake for like about a minute or two, make myself a cup of coffee, and come back to that damn thing still running! Luckily, I narrowed it down to the very root cause of it all: the logic that searches for the KaTeX binary in the machine.

I do not know how or why the heck is it so slow. In any case, I replaced it with a shutil's implementation of which, modified to work with the extension. And fortunately, it worked! The logic still looks the same as the old one, but the damn thing runs from 30 secs down to sub-five seconds, depending where the binary is at. Like, whaaaaaat?!?!

What is the moral of the story then? That someone's code might actually be the best solution for the problem. But if it does not work, then do not try to rebuild it from the ground up. See first if you can modify some parts of it to work with your problem. Then if it does not work, then proceed to rebuilding it. As often times, that solution might be the best solution for that exact problem, but not for your own, exact problem.

Or is that it?

Maybe I just wanted to rant about the stupid weeks I have wasted for this little thing to fucking work? Or is it because I just wanted to flex how much I have optimized a single thing?

I do not fucking know, but I sure did flex'd to my friends about how I "optimized" a program to run 40x faster. I mean, where is the lie?

Now, where am I again? Oh, right, KaTeX support. Yay, finally added! UwU

\ No newline at end of file diff --git a/dev/site/docs/0/0/api/cli/index.html b/dev/site/docs/0/0/api/cli/index.html index 48b072a..173e8a1 100644 --- a/dev/site/docs/0/0/api/cli/index.html +++ b/dev/site/docs/0/0/api/cli/index.html @@ -1,3 +1,3 @@ - **[src](index.md).[cli](cli.md)** - md2pdf

src.cli

Functions

hmc

(raw_HTML: str, HTML_path: str, raw_MD: str, MD_path: str, hf: bool | None = None) > str
+ **[src](index.md).[cli](cli.md)** - md2pdf        
         
        

src.cli

Functions

hmc

(raw_HTML: str, HTML_path: str, raw_MD: str, MD_path: str, hf: bool | None = None) > str
 

HTML or Markdown chooser.

Return first argument that is not None and convert it into HTML, if it is not already.

Args:

  • raw_HTML (str): Raw HTML string.
  • HTML_path (str): Path to HTML file.
  • raw_MD (str): Raw Markdown string.
  • MD_path (str): Path to Markdown file.

Returns:

string: Raw HTML string.

mc

(raw_MD: str, MD_path: str, hf: bool | None = None) > str | None
-

Markdown chooser.

Return first argument that is not None and convert it into HTML.

Args:

  • raw_MD (str): Raw Markdown string.
  • MD_path (str): Path to Markdown file.

Returns:

string: Raw HTML string.

\ No newline at end of file +

Markdown chooser.

Return first argument that is not None and convert it into HTML.

Args:


  • raw_MD (str): Raw Markdown string.
  • MD_path (str): Path to Markdown file.

Returns:


string: Raw HTML string.

\ No newline at end of file diff --git a/dev/site/docs/0/0/api/globals/index.html b/dev/site/docs/0/0/api/globals/index.html index 980e558..673ebcd 100644 --- a/dev/site/docs/0/0/api/globals/index.html +++ b/dev/site/docs/0/0/api/globals/index.html @@ -1 +1 @@ - **[src](index.md).[globals](globals.md)** - md2pdf
\ No newline at end of file + **[src](index.md).[globals](globals.md)** - md2pdf
\ No newline at end of file diff --git a/dev/site/docs/0/0/api/index.html b/dev/site/docs/0/0/api/index.html index 73b8b7d..de2a3a3 100644 --- a/dev/site/docs/0/0/api/index.html +++ b/dev/site/docs/0/0/api/index.html @@ -1 +1 @@ - **[src](index.md)** - md2pdf
\ No newline at end of file + **[src](index.md)** - md2pdf
\ No newline at end of file diff --git a/dev/site/docs/0/0/api/info/index.html b/dev/site/docs/0/0/api/info/index.html index 027fdb5..2ef5df2 100644 --- a/dev/site/docs/0/0/api/info/index.html +++ b/dev/site/docs/0/0/api/info/index.html @@ -1 +1 @@ - **[src](index.md).[info](info.md)** - md2pdf

src.info

Variables

CHOLDER HTML text of copyright holders of this project

PROJECT_NAME Project's name

SVER The current version of the project, compliant with the semver.

This project uses a modified semver. For more information, visit this link.

VARIANT The application variant

This is useful for debugging, and for initializing the application's configuration. Following are the allowed variants:

  • installable: for when the application is packed as an installable application
  • package: for when the application is published on PyPi (as a Python Library)
  • portable: for when the application is packed as a portable application

VLS The current version of the project as a list.

The list consists of 6 integers, which represent the following: - User - Dev - Minor - Patch - Prerelease Identifier The prerelease identifier number corresponds to the following values: 0: alpha 1: beta 2: release candidate or rc 3: none - Prerelease Version

\ No newline at end of file + **[src](index.md).[info](info.md)** - md2pdf

src.info

Variables

CHOLDER HTML text of copyright holders of this project

PROJECT_NAME Project's name

SVER The current version of the project, compliant with the semver.

This project uses a modified semver. For more information, visit this link.

VARIANT The application variant

This is useful for debugging, and for initializing the application's configuration. Following are the allowed variants:

  • installable: for when the application is packed as an installable application
  • package: for when the application is published on PyPi (as a Python Library)
  • portable: for when the application is packed as a portable application

VLS The current version of the project as a list.

The list consists of 6 integers, which represent the following: - User - Dev - Minor - Patch - Prerelease Identifier The prerelease identifier number corresponds to the following values: 0: alpha 1: beta 2: release candidate or rc 3: none - Prerelease Version

\ No newline at end of file diff --git a/dev/site/docs/0/0/api/md_pp/index.html b/dev/site/docs/0/0/api/md_pp/index.html index b7edb9d..3b7a12b 100644 --- a/dev/site/docs/0/0/api/md_pp/index.html +++ b/dev/site/docs/0/0/api/md_pp/index.html @@ -1,4 +1,4 @@ - **[src](index.md).[md_pp](md_pp.md)** - md2pdf

src.md_pp

Functions

get_bin_cmd

() > list[str]
+ **[src](index.md).[md_pp](md_pp.md)** - md2pdf        
         
        

src.md_pp

Functions

get_bin_cmd

() > list[str]
 

htmlsvg2img

(html: str) > str
 

katex2html

(marker: str, tex: str) > tuple[str, str]
 

make_marker_id

(text: str) > str
@@ -10,4 +10,4 @@
 

Each subclass of Preprocessor should override the run method, which takes the document as a list of strings split by newlines and returns the (possibly modified) list of lines.

WhExtension

(**kwargs: dict[str, typing.Any])
 

Base class for extensions to subclass.

Initiate Extension and set up configs.

Ancestors (in MRO)

  • markdown.extensions.Extension

Methods

extendMarkdown

(self, md: markdown.core.Markdown) > None
 

Add the various processors and patterns to the Markdown Instance.

This method must be overridden by every extension.

Keyword arguments:

  • md: The Markdown instance.

  • md_globals: Global variables in the markdown module namespace.

reset

(self) > None
-
\ No newline at end of file +
\ No newline at end of file diff --git a/dev/site/docs/0/0/api/pdfgenerator/index.html b/dev/site/docs/0/0/api/pdfgenerator/index.html index 9a3aa80..c1f28bb 100644 --- a/dev/site/docs/0/0/api/pdfgenerator/index.html +++ b/dev/site/docs/0/0/api/pdfgenerator/index.html @@ -1,6 +1,6 @@ - **[src](index.md).[pdfgenerator](pdfgenerator.md)** - md2pdf

src.pdfgenerator

Functions

calc_margin

(margin: list[float], header_height: int, footer_height: int) > str
+ **[src](index.md).[pdfgenerator](pdfgenerator.md)** - md2pdf        
         
        

src.pdfgenerator

Functions

calc_margin

(margin: list[float], header_height: int, footer_height: int) > str
 

get_element

(boxes, element)
 

Given a set of boxes representing the elements of a PDF page in a DOM-like way, find the box which is named element.

Notes: - When Weasyprint renders an html into a PDF, it goes though several intermediate steps. Here, in this class, we deal mostly with a box representation: 1 Document have 1 Page or more, each Page 1 Box or more. Each box can contain other box. Hence the recursive method get_element for example. For more, visit the following links: - https://weasyprint.readthedocs.io/en/stable/hacking.html#dive-into-the-source - https://weasyprint.readthedocs.io/en/stable/hacking.html#formatting-structure

margin_preprocessor

(margin: list[str]) > list[float]
 

Classes

PDFGenerator

(*, main_html: str, stylesheets: list[str], first_page_header_html=builtins.str, first_page_footer_html=builtins.str, header_html: str, footer_html: str, base_url: str, size: str, margin: list[str])
 

Generate a PDF out of a rendered template, with the possibility to integrate nicely a header and a footer if provided.

Notes: - Warning: the logic of this class relies heavily on the internal Weasyprint API. This snippet was written at the time of the release 47, it might break in the future. - This generator draws its inspiration and, also a bit of its implementation, from this discussion in the library github issues: https://github.com/Kozea/WeasyPrint/issues/92 - Hello from whi_ne (https://github.com/whinee) in the past, modified slightly at the time of release 51. And yes, I struggled adding my own features.

Initialize PDF Generator.

Notes: - The size and margin arguments are applied to the PDF like CSS does. See https://developer.mozilla.org/en-US/docs/Web/CSS/@page/size and https://developer.mozilla.org/en-US/docs/Web/CSS/margin#syntax respectively for more details.

Args:

  • main_html (str): An HTML file (most of the time a template rendered into a string) which represents the core of the PDF to generate.
  • first_page_header_html (str): Optional HTML for the first page's header.
  • first_page_footer_html (str): Optional HTML for the first page's footer.
  • header_html (str): Optional HTML for header.
  • footer_html (str): Optional HTML for footer.
  • base_url (str): An absolute url to the page which serves as a reference to Weasyprint to fetch assets, required to get our media.
  • stylesheets (list[str]): Optional paths to stylesheets to be used for rendering the PDF.
  • size (str): CSS size property applied directly to each page.
  • margin (str): CSS margin property applied directly to each page.

Methods

render_pdf

(self) > bytes
-

Return the rendered PDF.

Returns:

bytes: The rendered PDF.

\ No newline at end of file +

Return the rendered PDF.

Returns:

bytes: The rendered PDF.

\ No newline at end of file diff --git a/dev/site/docs/0/0/api/utils/base_cli/index.html b/dev/site/docs/0/0/api/utils/base_cli/index.html index 4663e8a..507ba3c 100644 --- a/dev/site/docs/0/0/api/utils/base_cli/index.html +++ b/dev/site/docs/0/0/api/utils/base_cli/index.html @@ -1,4 +1,4 @@ - **[src](../index.md).[utils](../utils.md).[base_cli](base_cli.md)** - md2pdf

src.utils.base_cli

Functions

command

(group: src.utils.base_cli.Group) > Callable[[Callable[..., Any]], Callable[..., Any]]
+ **[src](../index.md).[utils](../utils.md).[base_cli](base_cli.md)** - md2pdf        
         
        

src.utils.base_cli

Hereunder resides functions for constructing CLI for this program.

This module heavily documents my descent to madness.

An unholy amalgamation of megalamonia, depression, God complex, and impostor syndrome filled my broken heart.

This file is the digital manifestation of my mental woes.

Masochistic tendencies fuelling my coding sessions.

I wish upon this abyss to not touch this file ever again.

whi~nyaan! ― 2023

Functions

command

(group: src.utils.base_cli.Group) > Callable[[Callable[..., Any]], Callable[..., Any]]
 

Wrapper for click commands.

Args:

  • group (Group): Command group of the command to be under.

Returns:

  • Callable[[Callable[..., Any]], Callable[..., Any]]

command_group

(name: Union[str, Callable[..., Any], ForwardRef(None)] = None, **attrs: Any) > src.utils.base_cli.Group
 

custom_command

(name: Union[str, Callable[..., Any], ForwardRef(None)] = None, cls: Optional[Type[src.utils.base_cli.Command]] = None, **attrs: Any) > Union[src.utils.base_cli.Command, Callable[..., src.utils.base_cli.Command]]
 

de_rcfg

() > src.utils.cd.CustomDict
@@ -11,10 +11,10 @@
 

Returns the help option object.

Group

(name: str | None = None, commands: Union[Dict[str, click.core.Command], Sequence[click.core.Command], ForwardRef(None)] = None, **attrs: Any)
 

A group allows a command to have subcommands attached. This is the most common way to implement nesting in Click.

:param name: The name of the group command. :param commands: A dict mapping names to :class:Command objects. Can also be a list of :class:Command, which will use :attr:Command.name to create the dict. :param attrs: Other command arguments described in :class:MultiCommand, :class:Command, and :class:BaseCommand.

.. versionchanged:: 8.0 The commmands argument can be a list of command objects.

Ancestors (in MRO)

  • click.core.Group
  • click.core.MultiCommand
  • click.core.Command
  • click.core.BaseCommand

Methods

command

(self, *args: Any, **kwargs: Any) > Union[Callable[[Callable[..., Any]], src.utils.base_cli.Command], src.utils.base_cli.Command]
 

A shortcut decorator for declaring and attaching a command to the group. This takes the same arguments as :func:command and immediately registers the created command with this group by calling :meth:add_command.

To customize the command class used, set the :attr:command_class attribute.

.. versionchanged:: 8.1 This decorator can be applied without parentheses.

.. versionchanged:: 8.0 Added the :attr:command_class attribute.

cao

(group: src.utils.base_cli.Group)
-

Returns wrappers for a click command evaluated from the given arguments.

Args:

  • group (Group): Command group of the command to be under.

Methods

arguments

(self) > Callable[[Callable[..., Any]], Callable[..., Any]]
+

Returns wrappers for a click command evaluated from the given arguments.

Initialize object.

Args:

  • group (Group): Command group of the command to be under.

Methods

arguments

(self) > Callable[[Callable[..., Any]], Callable[..., Any]]
 

The arguments wrapper.

Returns:

Callable[[Callable[..., Any]], Callable[..., Any]]

command

(self) > Callable[[Callable[..., Any]], Callable[..., Any]]
 

The command wrapper.

Returns:

Callable[[Callable[..., Any]], Callable[..., Any]]

kwargs_preprocessor

(self, func: Callable[..., Any]) > Callable[..., Any]
 

option_the

(self, maxlen_type_string: int, maxlen_opts_help: int) > Callable[..., tuple[str, str, str]]
 

options

(self) > Callable[[Callable[..., Any]], Callable[..., Any]]
-

The options wrapper. My God in heaven, I'm agnostic, but please save me from all evil. Amen.

Returns:

Callable[[Callable[..., Any]], Callable[..., Any]]

wrap

(self, func: Callable[..., Any]) > Callable[..., Any]
-

Args:

  • func (Callable[..., Any]): Function to be wrapped.

Returns:

Callable[..., Any]: Wrapped function.

\ No newline at end of file +

The options wrapper.

My God in heaven, I'm agnostic, but please save me from all evil. Amen.

Returns:

Callable[[Callable[..., Any]], Callable[..., Any]]

wrap

(self, func: Callable[..., Any]) > Callable[..., Any]
+

Wrap given function with corresponding click decorators.

Args:

  • func (Callable[..., Any]): Function to be wrapped.

Returns:

Callable[..., Any]: Wrapped function.

\ No newline at end of file diff --git a/dev/site/docs/0/0/api/utils/base_exc/index.html b/dev/site/docs/0/0/api/utils/base_exc/index.html index ce19a35..8a682fb 100644 --- a/dev/site/docs/0/0/api/utils/base_exc/index.html +++ b/dev/site/docs/0/0/api/utils/base_exc/index.html @@ -1,3 +1,3 @@ - **[src](../index.md).[utils](../utils.md).[base_exc](base_exc.md)** - md2pdf

src.utils.base_exc

Functions

c_exc

(cls: Type[BaseException]) > Type[BaseException]
+ **[src](../index.md).[utils](../utils.md).[base_exc](base_exc.md)** - md2pdf        
         
        

src.utils.base_exc

Functions

c_exc

(cls: Type[BaseException]) > Type[BaseException]
 

Decorator to raise a custom exception.

This function gives the class an init function that raises the exception. If the class does not inherit from any Exception, it will be automatically inherit from Exception. This function also wraps the Exception with c_exc_str method, for adding the __str__ method.

Args:

  • cls (BaseException | Object): The exception to modify.

Returns:

BaseException: The exception to raise.

c_exc_str

(cls: Type[BaseException]) > Type[BaseException]
-

Decorator to add the str method to an exception.

Args:

  • cls (BaseException): The exception to add the str method to.

Returns:

BaseException: The exception to raise.

\ No newline at end of file +

Decorator to add the str method to an exception.

Args:

  • cls (BaseException): The exception to add the str method to.

Returns:

BaseException: The exception to raise.

\ No newline at end of file diff --git a/dev/site/docs/0/0/api/utils/cd/index.html b/dev/site/docs/0/0/api/utils/cd/index.html index c9aba34..36e425a 100644 --- a/dev/site/docs/0/0/api/utils/cd/index.html +++ b/dev/site/docs/0/0/api/utils/cd/index.html @@ -1,9 +1,9 @@ - **[src](../index.md).[utils](../utils.md).[cd](cd.md)** - md2pdf

src.utils.cd

Functions

test

() > None
+ **[src](../index.md).[utils](../utils.md).[cd](cd.md)** - md2pdf        
         
        

src.utils.cd

Functions

test

() > None
 

Classes

BEHAVIOR

(value, names=None, *, module=None, qualname=None, type=None, start=1)
 

An enumeration.

Ancestors (in MRO)

  • enum.Enum

Class variables

append

insert

modify

CustomDict

(*args, **kwargs)
 

Custom dictionary.

Ancestors (in MRO)

  • builtins.dict

Methods

dir

(self, path: str = 'c0VjUmVUX2NPZEUgYnkgd2hpX25l', de: Any = 'c0VjUmVUX2NPZEUgYnkgd2hpX25l', sep: str = '/') > Any
 

traverse

(self, path: str, elem: Union[dict[str, Any], Sized], sep: str, idx: int = 0, og_path: str | None = None) > Union[tuple[int, Union[Any, dict[str, int]]], Any]
-

summary

Return States | State || Return Type || Description | |--------:|-------------------------------------------:|:----------------------------------| | 0 || Any (Indexed Item) || Path fully traversed | | 1 || dict[str, int] (Kwargs for CDKeyError) || Path's not in element | | 2 || dict[str, int] (Kwargs for CDIndexError) || Path's current index not in range |

Callback States | State || Arguments Type || Description | |--------:|---------------------------------------------:|:-------------------------------------------| | 0 || dict (Indexed Item), str (key), int (idx) || Path fully traversed; Element type dict | | 1 || Sized (Indexed Item), int (key), int (idx) || Path fully traversed; Element type Sized |

Args:

path (str): _description_
+

summary.

Return States | State || Return Type || Description | |--------:|-------------------------------------------:|:----------------------------------| | 0 || Any (Indexed Item) || Path fully traversed | | 1 || dict[str, int] (Kwargs for CDKeyError) || Path's not in element | | 2 || dict[str, int] (Kwargs for CDIndexError) || Path's current index not in range |

Callback States | State || Arguments Type || Description | |--------:|---------------------------------------------:|:-------------------------------------------| | 0 || dict (Indexed Item), str (key), int (idx) || Path fully traversed; Element type dict | | 1 || Sized (Indexed Item), int (key), int (idx) || Path fully traversed; Element type Sized |

Args:

path (str): _description_
 elem (dict[str, Any] | Sized): _description_
 sep (str): _description_
 idx (int, optional): _description_. Defaults to 0.
@@ -35,4 +35,4 @@
                         j ----> |yes| c
 
     classDef success color:#83ce9e,stroke:#6fc890
-    classDef error color:#f3626b,stroke:#f14651
\ No newline at end of file + classDef error color:#f3626b,stroke:#f14651
\ No newline at end of file diff --git a/dev/site/docs/0/0/api/utils/cfg/index.html b/dev/site/docs/0/0/api/utils/cfg/index.html index e1d9409..a9f14be 100644 --- a/dev/site/docs/0/0/api/utils/cfg/index.html +++ b/dev/site/docs/0/0/api/utils/cfg/index.html @@ -1,6 +1,6 @@ - **[src](../index.md).[utils](../utils.md).[cfg](cfg.md)** - md2pdf

src.utils.cfg

Functions

dcfg

(value: dict[str, typing.Any], ext: str) > str
+ **[src](../index.md).[utils](../utils.md).[cfg](cfg.md)** - md2pdf        
         
        

src.utils.cfg

Functions

dcfg

(value: dict[str, typing.Any], ext: str) > str
 

Dump the given value to a string with the given extension.

Args:

  • value (dict): Value to dump to a string.
  • ext (str): Extension to dump the value to.

Returns:

str: The dumped value.

pcfg

(d: str, type: str) > src.utils.cd.CustomDict
 

Parse the given string as the given type.

Args:

  • d (str): String to parse.
  • type (str): Type to parse the string as.

Returns:

CustomDict: The parsed string.

rcfg

(file: str) > src.utils.cd.CustomDict
 

Read the contents of a file with the given file name.

Args:

  • file (str): File name of the file to read the contents of.

Returns:

CustomDict: The contents of the file.

wcfg

(file: str, value: dict[typing.Any, typing.Any] | list[typing.Any]) > None
 

Write the given value to a file with the given file name.

Args:

  • file (str): File name of the file to write the value to.
  • value (dict[Any, Any] | list[Any]): Value to write to the file.

Classes

ExtensionNotSupported

(*args: list[typing.Any], **kwargs: dict[str, typing.Any])
-

Method or function hasn't been implemented yet.

Ancestors (in MRO)

  • builtins.NotImplementedError
  • builtins.RuntimeError
  • builtins.Exception
  • builtins.BaseException
\ No newline at end of file +

Method or function hasn't been implemented yet.

Ancestors (in MRO)

  • builtins.NotImplementedError
  • builtins.RuntimeError
  • builtins.Exception
  • builtins.BaseException
\ No newline at end of file diff --git a/dev/site/docs/0/0/api/utils/exceptions/index.html b/dev/site/docs/0/0/api/utils/exceptions/index.html index 2c9b351..0ed403e 100644 --- a/dev/site/docs/0/0/api/utils/exceptions/index.html +++ b/dev/site/docs/0/0/api/utils/exceptions/index.html @@ -1,5 +1,5 @@ - **[src](../index.md).[utils](../utils.md).[exceptions](exceptions.md)** - md2pdf

src.utils.exceptions

Classes

CDExceptions

()
+ **[src](../index.md).[utils](../utils.md).[exceptions](exceptions.md)** - md2pdf        
         
        
\ No newline at end of file +

Class variables

NotFound Common base class for all non-exit exceptions.

\ No newline at end of file diff --git a/dev/site/docs/0/0/api/utils/index.html b/dev/site/docs/0/0/api/utils/index.html index b7d3cb3..c1602e4 100644 --- a/dev/site/docs/0/0/api/utils/index.html +++ b/dev/site/docs/0/0/api/utils/index.html @@ -1 +1 @@ - **[src](index.md).[utils](utils.md)** - md2pdf
\ No newline at end of file + **[src](index.md).[utils](utils.md)** - md2pdf
\ No newline at end of file diff --git a/dev/site/docs/0/0/api/utils/style/index.html b/dev/site/docs/0/0/api/utils/style/index.html index a77353c..f7762b4 100644 --- a/dev/site/docs/0/0/api/utils/style/index.html +++ b/dev/site/docs/0/0/api/utils/style/index.html @@ -1,4 +1,4 @@ - **[src](../index.md).[utils](../utils.md).[style](style.md)** - md2pdf

src.utils.style

Variables

COLORS t1: F3F78D t2: FF8D5C t3: E84855 t4: B56B45 t5: 404E7C t6: 55828B t7: 4E8098

Functions

pp

(t: Any, ca: bool | None = None, *args: list[typing.Any], **kwargs: dict[str, typing.Any]) > None
+ **[src](../index.md).[utils](../utils.md).[style](style.md)** - md2pdf        
         
        

src.utils.style

Variables

COLORS t1: F3F78D t2: FF8D5C t3: E84855 t4: B56B45 t5: 404E7C t6: 55828B t7: 4E8098

Functions

pp

(t: Any, ca: bool | None = None, *args: list[typing.Any], **kwargs: dict[str, typing.Any]) > None
 

Center rich printable objects, then pretty print it.

Args:

  • t (Any): Rich printable object to be centered, then pretty printed.
  • ca (bool, optional): Determines whether to center text in the group individually. Defaults to None.

split_text

(t: str) > list[str]
 

text

(t: str, *args: list[typing.Any], ca: bool | None = None, **kwargs: dict[str, typing.Any]) > rich.console.Group
 

Classes

C

()
@@ -6,4 +6,4 @@
 

Class variables

p0

p1

p_critical

p_error

p_warning

t0

t1

t2

t3

t4

t5

t6

t_critical

t_error

t_good

t_warning

ct

()
 

Static methods

group

(*ls: rich.console.ConsoleRenderable | rich.console.RichCast | str) > rich.console.Group
 

Group given list of rich printable objects.

Returns:

Group: Group of rich printable objects

table

(cols: list[str], rows: list[list[str]]) > None
-

Print table from given list of str and list of list of strings for the columns and rows respectively.

Args:

  • cols (list[str]): List of string for column labels.
  • rows (list[list[str]]): List of rows (list of strings).
\ No newline at end of file +

Print table from given list of str and list of list of strings for the columns and rows respectively.

Args:

  • cols (list[str]): List of string for column labels.
  • rows (list[list[str]]): List of rows (list of strings).
\ No newline at end of file diff --git a/dev/site/docs/0/0/api/utils/types/index.html b/dev/site/docs/0/0/api/utils/types/index.html index 1ee067f..5e7fb1d 100644 --- a/dev/site/docs/0/0/api/utils/types/index.html +++ b/dev/site/docs/0/0/api/utils/types/index.html @@ -1 +1 @@ - **[src](../index.md).[utils](../utils.md).[types](types.md)** - md2pdf
\ No newline at end of file + **[src](../index.md).[utils](../utils.md).[types](types.md)** - md2pdf
\ No newline at end of file diff --git a/dev/site/docs/0/0/api/utils/utils/index.html b/dev/site/docs/0/0/api/utils/utils/index.html index c8bb718..d7550ba 100644 --- a/dev/site/docs/0/0/api/utils/utils/index.html +++ b/dev/site/docs/0/0/api/utils/utils/index.html @@ -1,18 +1,18 @@ - **[src](../index.md).[utils](../utils.md).[utils](utils.md)** - md2pdf

src.utils.utils

Functions

dnrp

(file: str, n: Optional[int] = None) > str
+ **[src](../index.md).[utils](../utils.md).[utils](utils.md)** - md2pdf        
         
        

src.utils.utils

Functions

dnrp

(file: str, n: Optional[int] = None) > str
 

Get the directory component of a pathname by n times recursively then return it.

Args:

  • file (str): File to get the directory of.
  • n (Optional[int], optional): Number of times to get up the directory???? Defaults to 1.

Returns:

str: The directory component got recursively by n times from the given pathname

dpop

(d: dict[typing.Any, typing.Any], pop: list[int | list[str | int | tuple[str, ...]] | str], de: Optional[Any] = None) > Any
 

Iterate through the preferred order of precedence (pop) and see if the value exists in the dictionary. If it does, return it. If not, return de.

Args:

  • d (Dict[Any, Any]): Dictionary to retrieve the value from.
  • pop (list[int | tuple[str | int | tuple] | str]): List of keys to iterate through.
  • de (Any, optional): Default object to be returned. Defaults to None.

Returns:

Any: Retrieved value.

dt

(dt: str, format: str) > str
 

Remove timezone from datetime and format it to ISO 8601 format.

Args:

  • dt (str): Unformatted datetime string to be formatted to ISO 8601 format
  • format (str): The initial format of the datetime string

Returns:

str: Formatted datetime string

dt_ts

(ts: str) > str
 

Convert the given unix timestamp to ISO 8601 format.

Args:

  • ts (str): unix timestamp to be converted to ISO 8601 format

Returns:

str: Formatted datetime string

file_exists

(fp: str) > str
 

Check if the given file path exists.

Args:

  • fp (str): File path to check if it exists.

Raises:

  • exceptions.GeneralExceptions.ValidationError.FileNotFound: Raised when a file in the path is not found.

Returns:

str: Return fp when file path exists.

fill_ls

(*, ls: Sequence[Any], length: int, filler: Optional[Any] = None) > Sequence[Any]
 

Fill given list (ls) with filler up to length.

Args:

  • ls (types.SequenceAny): List to fill with filler up to length
  • length (int): Length of the list to achieve.
  • filler (Optional[Any], optional): Filler to use. Defaults to None.

Returns:

types.SequenceAny: Filled list.

inmd

(p: str, ls: Optional[list[str]] = None) > str
-

"If Not os.path.isdir, Make Directories"

Args:

  • p (str): The path to be created, if it does not exist.
  • ls(Optional[list[str]], optional): List to append directories to that are not found and successfully created. Defaults to None.

Returns:

str: The path given.

iter_ls_with_items

(ls: list[typing.Any], *items: list[typing.Any]) > Generator[tuple[Any, ...], None, None]
+

"If Not os.path.isdir, Make Directories".

Args:

  • p (str): The path to be created, if it does not exist.
  • ls(Optional[list[str]], optional): List to append directories to that are not found and successfully created. Defaults to None.

Returns:

str: The path given.

iter_ls_with_items

(ls: list[typing.Any], *items: list[typing.Any]) > Generator[tuple[Any, ...], None, None]
 

ivnd

(var: Any, de: Any) > Any
 

If Var is None, return Default else var.

Args:

  • var (Any): Variable to check if it is None.
  • de (Any): Default value to return if var is None.

Returns:

Any: var if var is not None else de.

le

(expr: str) > Any
-

Literal Evaluation

Args:

  • expr (str): Expression to be evaluated.

Returns:

Any: Expression literally evaluated.

noop

(*args: list[typing.Any], **kwargs: dict[str, typing.Any]) > None
-

No operation

noop_single_kwargs

(arg: Any) > Any
+

Literal Evaluation.

Args:

  • expr (str): Expression to be evaluated.

Returns:

Any: Expression literally evaluated.

noop

(*args: list[typing.Any], **kwargs: dict[str, typing.Any]) > None
+

No operation.

noop_single_kwargs

(arg: Any) > Any
 

repl

(s: str, repl_dict: dict[str, list[str]]) > str
 

Iterate through the dictionary, find the values in the given string and replace it with the corresponding key, and output the modified string.

Args:

  • s (str): String to modify.
  • repl_dict (dict[str, list[str]]): key-value pairs to replace string within the given string.

Returns:

str: Modified string.

rfnn

(*args: list[typing.Any]) > Any
-

Return First Non-None

Return the first argument that is not None, else return None.

Returns:

Any: The first argument that is not None, else None.

run_mp

(func: Callable[..., Any], iterable: Iterable[Any]) > list[typing.Any]
+

Return First Non-None.

Return the first argument that is not None, else return None.

Returns:

Any: The first argument that is not None, else None.

run_mp

(func: Callable[..., Any], iterable: Iterable[Any]) > list[typing.Any]
 

run_mp_qgr

(func: Callable[..., Any], iterable: Iterable[Any]) > tuple[None] | tuple[typing.Any] | tuple[typing.Any, ...]
 

run_mp_qir

(func: Callable[..., Any], iterable: Iterable[Any], callback: Callable[..., Any]) > None
 

Run multiprocessing.Pool().map_async(), and quit in return.

Iterate over iterable and apply iterated item to func asynchronously. Wait for a single process in the pool to return, and terminate the pool.

This function requires the given function to return a bool, or an iterable with its first item as a bool. This bool is then used to decide whether to trigger the callback and terminate the pool.

run_mp_star

(func: Callable[..., Any], iterable: Iterable[Iterable[Any]]) > list[typing.Any]
@@ -23,8 +23,8 @@
 

Custom search query.

Args:

  • query (str): String to search for in the possibilities.
  • possibilities (list[str]): The possibilities to search from.
  • cutoff (int | float, optional): The minimum percentage of similarity from the given possibilities. Defaults to 0.6.
  • processor (Callable[[Any], Any], optional): Processes the possibilities before comparing it with the query. Defaults to lambda x: x.

Returns:

Generator[tuple[None, str] | tuple[float, str], None, None]: Generator object of mastching search quries.

str2int

(s: str) > Optional[int]
 

If given string is decimal, convert string to integer, else return False.

Args:

s (str): string to convert to integer.
 

Returns:

bool: _description_
-

which_ls

(cmd: str, mode: Optional[int] = None, path: str | None = None) > Union[tuple[str], tuple[str, ...], ForwardRef(None)]
-

Yoinked from shutil. Given a command, mode, and a PATH string, return the path which conforms to the given mode on the PATH, or None if there is no such file.

mode defaults to os.F_OK | os.X_OK. path defaults to the result of os.environ.get("PATH"), or can be overridden with a custom search path.

Classes

CallbackGetResult

()
+

which_ls

(cmd: str, mode: Optional[int] = 1, path: str | None = '/home/whine/whi_ne/3/projects/personal/tools/md2pdf-rewrite/pyenv/bin:/home/whine/bin:/home/whine/whi_ne/2/.local:/home/whine/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl:/var/lib/snapd/snap/bin') > Union[tuple[str], tuple[str, ...], ForwardRef(None)]
+

Given a command, mode, and a PATH string, return the path which conforms to the given mode on the PATH, or None if there is no such file.

Notes: - Yoinked from shutil. - mode defaults to os.F_OK | os.X_OK. path defaults to the result of os.environ.get("PATH"), or can be overridden with a custom search path.

Args:

  • cmd (str): Executable to look for.
  • mode (Optional[int], optional): Executable permissions to look for. Defaults to os.F_OK | os.X_OK.
  • path (Optional[str], optional): The PATH to where the executable can be found. Defaults to os.environ.get("PATH", None).

Returns:

Optional[types.TupleStr]: List of path where executable is found at.

Classes

CallbackGetResult

()
 

Methods

callback

(self, *args: list[typing.Any]) > None
 

get

(self) > tuple[None] | tuple[typing.Any, ...]
 

ExtInquirerControl

(choices: Sequence[Union[str, questionary.prompts.common.Choice, Dict[str, Any]]], default: Union[str, questionary.prompts.common.Choice, Dict[str, Any], ForwardRef(None)] = None, pointer: str | None = '»', use_indicator: bool = True, use_shortcuts: bool = False, show_selected: bool = False, use_arrow_keys: bool = True, initial_choice: Union[str, questionary.prompts.common.Choice, Dict[str, Any], ForwardRef(None)] = None, **kwargs: Any)
@@ -38,4 +38,4 @@
 

A question to be prompted.

This is an internal class. Questions should be created using the predefined questions (e.g. text or password).

Ancestors (in MRO)

  • questionary.question.Question

Class variables

kbi

Methods

ask

(self, patch_stdout: bool | None = None, **kwargs: dict[str, typing.Any]) > tuple[bool, typing.Any]
 

Ask the question synchronously and return user response.

Args:

  • patch_stdout (bool, optional): Ensure that the prompt renders correctly if other threads are printing to stdout. Defaults to None.

Returns:

Any: The answer from the question.

PoolTerminate

(pool: multiprocessing.pool.Pool, callback: Callable[..., Any])
 

Methods

inner

(self, err: bool, *args: list[typing.Any], **kwargs: dict[str, typing.Any]) > None
-
\ No newline at end of file +
\ No newline at end of file diff --git a/dev/site/docs/0/0/contribute/index.html b/dev/site/docs/0/0/contribute/index.html index 599f37f..c02cf49 100644 --- a/dev/site/docs/0/0/contribute/index.html +++ b/dev/site/docs/0/0/contribute/index.html @@ -1 +1 @@ - Index - md2pdf
\ No newline at end of file + Index - md2pdf
\ No newline at end of file diff --git a/dev/site/docs/0/0/contribute/translations/index.html b/dev/site/docs/0/0/contribute/translations/index.html index a969dc8..14668f7 100644 --- a/dev/site/docs/0/0/contribute/translations/index.html +++ b/dev/site/docs/0/0/contribute/translations/index.html @@ -1,4 +1,4 @@ - Translations - md2pdf

Translations

Summary

While there are no future plans for expanding to the global audience, of which most does not speak English, this application is ready for internationalization.

Definition of Terms

i18n (abbreviation, numeronym): stands for internationalization; process of designing a software application so that it can be adapted to various languages and regions without engineering changes

Translation Directory

The files that contain the translations can be located at ./dev/constants/version/{u}/{d}/lang/

whereas:

  • {u} refers to the user version that uses the constants under this directory
  • {d} refers to the dev version that uses the constants under this directory
Notes: For more information, visit the notes for whi~nyaan!.

Notes for Translators

For those who want to translate this application, please read all of the following text.

Rule of Thumb

This is written by the author with no consideration for other languages. And as such, recommendations and suggestions are highly appreciated.

  • Any technical terminologies should be left untranslated, unless noted by the author (developer) otherwise.
  • Any technical phrase that cannot be translated properly to the target language should be translated without oversimplifying; Oversimplification might lead to a misunderstanding
  • Unless the tone affects the meaning of the text or unless stated otherwise, translators should not preserve the author's tone and should translate it with a neutral tone

Variables

You might see a text that is enclosed in a bracket, like the following:

{version}
+ Translations - md2pdf        
         
       

Translations

Summary

While there are no future plans for expanding to the global audience, of which most does not speak English, this application is ready for internationalization.

Definition of Terms

i18n (abbreviation, numeronym): stands for internationalization; process of designing a software application so that it can be adapted to various languages and regions without engineering changes

Translation Directory

The files that contain the translations can be located at ./dev/constants/version/{u}/{d}/lang/

whereas:

  • {u} refers to the user version that uses the constants under this directory
  • {d} refers to the dev version that uses the constants under this directory
Notes: For more information, visit the notes for whi~nyaan!.

Notes for Translators

For those who want to translate this application, please read all of the following text.

Rule of Thumb

This is written by the author with no consideration for other languages. And as such, recommendations and suggestions are highly appreciated.

  • Any technical terminologies should be left untranslated, unless noted by the author (developer) otherwise.
  • Any technical phrase that cannot be translated properly to the target language should be translated without oversimplifying; Oversimplification might lead to a misunderstanding
  • Unless the tone affects the meaning of the text or unless stated otherwise, translators should not preserve the author's tone and should translate it with a neutral tone

Variables

You might see a text that is enclosed in a bracket, like the following:

{version}
 

These are variables, and are replaced with information in the application before displaying them to the user.

So, our example would be displayed to the users as such:

69.4.20
 

As you can see, it is crucial for displaying information to the users.

When translating a piece of text, make sure to put these variables in an appropriate place, and do not translate its name.

As an example, we will translate this English text:

Thank you for using {app_name}!
 

To Tagalog:

Sa paggamit ng {app_name}, ako ay taos-pusong nagpapasalamat sa iyong pagtangkilik!
@@ -22,4 +22,4 @@
             str: Choose language
             desc: |-
                 Choose app language
-

{scope}

There are three scopes allowed, but only the first two are applicable:

  • common
  • cli
  • gui

The first scope is class of keys that can be used in both the CLI and GUI versions of the app. This includes the description and motto of the program, prompts like yes or no, and whatnot. The rest is self-explanatory.

{class}

This is where keys are categorized. For example, keys that convey information regarding the application can be put under the info class, while the keys that are used for prompting the users can be put under the prompt class.

{key}

This is the name of the key. There is no general naming convention, but the developer seems to have one in her mind.

str

The string in the language defined by the language file.

desc

Description of the key. Might be useful to keep the translation accurate at an acceptable margin. Will not be displayed.

tln

Stands for translators' notes, used by translators to describe to the next translators any compromises done to translate the text to a certain language, or whatnot.

\ No newline at end of file +

{scope}

There are three scopes allowed, but only the first two are applicable:

  • common
  • cli
  • gui

The first scope is class of keys that can be used in both the CLI and GUI versions of the app. This includes the description and motto of the program, prompts like yes or no, and whatnot. The rest is self-explanatory.

{class}

This is where keys are categorized. For example, keys that convey information regarding the application can be put under the info class, while the keys that are used for prompting the users can be put under the prompt class.

{key}

This is the name of the key. There is no general naming convention, but the developer seems to have one in her mind.

str

The string in the language defined by the language file.

desc

Description of the key. Might be useful to keep the translation accurate at an acceptable margin. Will not be displayed.

tln

Stands for translators' notes, used by translators to describe to the next translators any compromises done to translate the text to a certain language, or whatnot.

\ No newline at end of file diff --git a/dev/site/docs/0/0/index.html b/dev/site/docs/0/0/index.html index 61b4878..1e3a044 100644 --- a/dev/site/docs/0/0/index.html +++ b/dev/site/docs/0/0/index.html @@ -1 +1 @@ - Index - md2pdf
\ No newline at end of file + Index - md2pdf
\ No newline at end of file diff --git a/dev/site/docs/0/0/installation/index.html b/dev/site/docs/0/0/installation/index.html index fb0a3f2..8924540 100644 --- a/dev/site/docs/0/0/installation/index.html +++ b/dev/site/docs/0/0/installation/index.html @@ -1,4 +1,4 @@ - Installation - md2pdf

Installating md2pdf

Windows

  1. Copy the following text:

    Set-ExecutionPolicy Bypass -Scope Process -Force
    + Installation - md2pdf        
             
           

    Installating md2pdf

    Windows

    1. Copy the following text:

      Set-ExecutionPolicy Bypass -Scope Process -Force
       [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
       iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
       
    2. Press Win. An interface should pop up as shown below:

      1

    3. Search for settings by typing "Settings" in the text field as shown below:

      2

      Press Enter.

    4. A window should pop up as shown below:

      3

      Press "Apps" in the selection below.

    5. You should be redirected to "Apps & Features" as shown below:

      4

      Below the subtitle "Apps & Features", press the hyperlink "App execution aliases".

    6. You should be redirected to "App execution aliases" as shown below:

      5

      Toggle the "App installer" for both "python.exe" and "python3.exe". Exit the settings app.

    7. Press Windows + R (Press Windows and R keys simultaneously)

    8. A window with a title Run should appear. Focus to the said window in the Open: text field by hovering the mouse towards the said text field and left-clicking the mouse and type powershell as shown below:

    9. Press Ctrl + Shift + Enter (Press Ctrl, Shift, and Enter keys simultaneously).

    10. A window with a title User Account Control should appear as shown below:

    11. Focus to the said window and press the Yes button by hovering the mouse towards the said button and left-clicking the mouse. A window named Administrator: Windows Powershell should pop-up.

    12. Focus to the window named Administrator: Windows Powershell window by hovering the mouse towards the said window and left-clicking the mouse. Then, press Ctrl + V (Press Ctrl and V keys simultaneously).

      If the window Administrator: Windows Powershell seems to hang up, focus to said window by hovering the mouse towards the said window and left-clicking the mouse, then press Enter five times every minute or so until something happens.

    13. Restart your computer, then login to the user account to which you have done the above instructions at.

    14. Copy the following text:

      choco install nodejs -y
      @@ -13,4 +13,4 @@
       

      1. Afterwards, install the rest of the prerequisites by running the following command:

        brew install node
         

      2. Then, install katex with npm by running the following command:

        npm install katex
         

      Linux

      Arch

      1. Open your preferred terminal and run the following command:
        sudo pacman -Syyu --noconfirm curl
        -
    \ No newline at end of file +
\ No newline at end of file diff --git a/dev/site/docs/0/0/markdown/index.html b/dev/site/docs/0/0/markdown/index.html index 5d46eca..db2425f 100644 --- a/dev/site/docs/0/0/markdown/index.html +++ b/dev/site/docs/0/0/markdown/index.html @@ -1,7 +1,7 @@ - Markdown - md2pdf

Markdown Implementation

Base Implementation

md2pdf uses Python-Markdown/markdown to convert Markdown to HTML which, apparently, is a Python implementation of John Gruber's markdown

According to the cited program's documentation, the specification is implemented as close to the reference specification as possible. In this link, you will see difference of the Python implementation and the original implementation.

And oh yes, this is an arguably messy implementation of Markdown, as opposed to Commonmark Markdown. But we got to make do of what we have, no? baka baka :3

Extended Syntax

md2pdf extended the base implementation, and hereinunder are the details.

Math Expression

KaTeX expressions are supported in this program. You just need to surround it in a code block, with the language set as math. An example of this is the following:

```math
+ Markdown - md2pdf        
         
       

Markdown Implementation

Base Implementation

md2pdf uses Python-Markdown/markdown to convert Markdown to HTML which, apparently, is a Python implementation of John Gruber's markdown

According to the cited program's documentation, the specification is implemented as close to the reference specification as possible. In this link, you will see difference of the Python implementation and the original implementation.

And oh yes, this is an arguably messy implementation of Markdown, as opposed to Commonmark Markdown. But we got to make do of what we have, no? baka baka :3

Extended Syntax

md2pdf extended the base implementation, and hereinunder are the details.

Math Expression

KaTeX expressions are supported in this program. You just need to surround it in a code block, with the language set as math. An example of this is the following:

```math
 % \f is defined as #1f(#2) using the macro
 \f\relax{x} = \int_{-\infty}^\infty
     \f\hat\xi\,e^{2 \pi i \xi x}
     \,d\xi
 ```
-

This link lists all of the supported functions in KaTeX, grouped logically.

\ No newline at end of file +

This link lists all of the supported functions in KaTeX, grouped logically.

\ No newline at end of file diff --git a/dev/site/docs/0/index.html b/dev/site/docs/0/index.html index 21c496c..e603371 100644 --- a/dev/site/docs/0/index.html +++ b/dev/site/docs/0/index.html @@ -1 +1 @@ - Index - md2pdf
\ No newline at end of file + Index - md2pdf
\ No newline at end of file diff --git a/dev/site/docs/index.html b/dev/site/docs/index.html index b3c6d50..99dfa27 100644 --- a/dev/site/docs/index.html +++ b/dev/site/docs/index.html @@ -1 +1 @@ - Index - md2pdf
\ No newline at end of file + Index - md2pdf
\ No newline at end of file diff --git a/dev/site/faq/index.html b/dev/site/faq/index.html index 3d0dcc0..63c6e4c 100644 --- a/dev/site/faq/index.html +++ b/dev/site/faq/index.html @@ -1 +1 @@ - Faq - md2pdf

FAQ

Is this application safe?

TL;DR: First of all, safe from what aspect, bruv? Considering that you are asking this, probably not.

Is this application safe for my computer?

TL;DR: Yes, but not really. Safe enough to put a 99.99% safety guarantee on it, air commercials of it, and not get sued on the grounds of false advertisement.

No software is ever safe, and there will never be. Unless if we, for some mysterious and divine reason, gain the ability to prove if a program halts or not, which in this universe is impossible (relevant link: Halting problem).

Enough of explaining the philosophical implications of this problematic question, and let us go to the real meat of the discussion. No, I can not assure you, as the developer of this application, that this application is safe. It is like asking if I poisoned your food; regardless of if I did it or not, I will dutifully deny the allegation, duh. Inquired you did, now trust me. Make of that what you will, but I am here to chase clout and make money out of it, not to compromise machines.

Well, with all that said, I also made it for personal use. And for that, I have to make it at the very least usable to the extent that it would not compromise the host machine that it is running on.

Don't trust me? The application is open-sourced. Every packaged application downloaded from the official site and Github repository is built from the same source as available on the official Github repository. If you know how to read the source code, you are free to do so, and inspect it. If you did do so, please hunt down some bugs for me. Much appreciated UwU

To end this answer, well... I mean, you could run the thing on a virus checker. Although, what might be an innocuous yet insecure system API call might be flagged as a suspicious activity. Not that I am aware of anything of that sort in my application, but I think that that will suffice as an example.

What are your intentions in making this application?

TL;DR: It's a hobby of mine. It is not driven by money or ill intentions. Inquired you did, now trust me.

This started out as a hobby project. To pass time, and live out the rest of my days as a virgin NEET and a total social recluse. Assuming that you can see this site right now, it has grew into this large and popular project that it has become.

My intentions however are still the same as it was months ago. However, I have a side goal in mind right now: to attain popularity in the open source scene, enough to get me enough freelancing work and earn money.

Yes, that is it, really. I am in it for the money, but the development of this application is but money-driven. I mean, I would very much appreciate it if you could donate money or a little bit of your time to this little endeavour of mine, or commission me to do some work for you.

Who are you?

TL;DR: That's a creepy thing to ask dude, I'm a teenager. \s

Hello, I am whi_ne, short for whitespace_negative. 17 at the time of writing. I am a python and a web developer, albeit shitty at both of them. I also do some freelance work. Nice to meet ya!

Yes, I use an alias; personal branding is dead. I also want to stay anonymous. However, my pics on multiple guys' DMs suggests otherwise. And yes, please do not dig up dirt on me, I will let you know everything there is to know about me.

\ No newline at end of file + Faq - md2pdf

FAQ

Is this application safe?

TL;DR: First of all, safe from what aspect, bruv? Considering that you are asking this, probably not.

Is this application safe for my computer?

TL;DR: Yes, but not really. Safe enough to put a 99.99% safety guarantee on it, air commercials of it, and not get sued on the grounds of false advertisement.

No software is ever safe, and there will never be. Unless if we, for some mysterious and divine reason, gain the ability to prove if a program halts or not, which in this universe is impossible (relevant link: Halting problem).

Enough of explaining the philosophical implications of this problematic question, and let us go to the real meat of the discussion. No, I can not assure you, as the developer of this application, that this application is safe. It is like asking if I poisoned your food; regardless of if I did it or not, I will dutifully deny the allegation, duh. Inquired you did, now trust me. Make of that what you will, but I am here to chase clout and make money out of it, not to compromise machines.

Well, with all that said, I also made it for personal use. And for that, I have to make it at the very least usable to the extent that it would not compromise the host machine that it is running on.

Don't trust me? The application is open-sourced. Every packaged application downloaded from the official site and Github repository is built from the same source as available on the official Github repository. If you know how to read the source code, you are free to do so, and inspect it. If you did do so, please hunt down some bugs for me. Much appreciated UwU

To end this answer, well... I mean, you could run the thing on a virus checker. Although, what might be an innocuous yet insecure system API call might be flagged as a suspicious activity. Not that I am aware of anything of that sort in my application, but I think that that will suffice as an example.

What are your intentions in making this application?

TL;DR: It's a hobby of mine. It is not driven by money or ill intentions. Inquired you did, now trust me.

This started out as a hobby project. To pass time, and live out the rest of my days as a virgin NEET and a total social recluse. Assuming that you can see this site right now, it has grew into this large and popular project that it has become.

My intentions however are still the same as it was months ago. However, I have a side goal in mind right now: to attain popularity in the open source scene, enough to get me enough freelancing work and earn money.

Yes, that is it, really. I am in it for the money, but the development of this application is but money-driven. I mean, I would very much appreciate it if you could donate money or a little bit of your time to this little endeavour of mine, or commission me to do some work for you.

Who are you?

TL;DR: That's a creepy thing to ask dude, I'm a teenager. \s

Hello, I am whi_ne, short for whitespace_negative. 17 at the time of writing. I am a python and a web developer, albeit shitty at both of them. I also do some freelance work. Nice to meet ya!

Yes, I use an alias; personal branding is dead. I also want to stay anonymous. However, my pics on multiple guys' DMs suggests otherwise. And yes, please do not dig up dirt on me, I will let you know everything there is to know about me.

\ No newline at end of file diff --git a/dev/site/index.html b/dev/site/index.html index 476d596..14f87ab 100644 --- a/dev/site/index.html +++ b/dev/site/index.html @@ -1 +1 @@ - md2pdf

md2pdf

Markdown to PDF converter

wakatime Codacy Badge GitHub release (latest by date including pre-releases) GitHub Workflow Status


For writing faster? No. For writing with *class*? Yusss


Github: github.com/whinee/md2pdf

Website: m2p.whinyaan.xyz


To be updated, be sure to watch this repository and join the Discord Support Server for this and other projects.

Interested in commissioning projects? Inquire through Discord(whi_ne#4783) or through e-mail(whinyaan@protonmail.com). Price starts at 30 USD.

Important

md2pdf is still in Unreleased Alpha Development Stage.

Using the program at this stage is not recommended.

Downloads

Since people are looking for the download first, here you go:

Follow this link to install md2pdf in your machine.

What’s this?

md2pdf is a Markdown to PDF converter that can also do a lot of stuff:

  • Headers and Footers
    • Can be in Markdown or HTML format
    • Support for first page header and footer
  • Print output HTML
  • Programmatic Usage

Supported OSes

  • Windows
  • MacOS
  • Linux

Usage

This section is not yet complete.

Getting Started

The instructions will get you a copy of the project up and running on your local machine for development and testing purposes., visit this link

Advantages

  • Standardized Styles
  • Consistent Results
  • Programmatic Usage

Disadvantages

  • This program does not guarantee that you will be able to write faster, just be able to write in markdown (effectively plaintext) and produce consistent results (assuming that you use the same text, settings, stylesheet/s, and whatnot)
  • Have to link pictures online in order to attach one in the document, unlike in fancy word editors like Microsoft Word or LibreOffice Writer

Translations

This program is translation (i18n) ready!

Please refer to this link to learn more on how to create a translation for this program.

Known Issues and Limitations

  • This program can not be run in termux due to an inherent bug in AOSP that the said org's developers refuses to fix even if it will only take (apparently) a change in a single line of code (I forgot where the relevant Stackoverflow link is stored at, nor do I know the keywords for searching it up)

Considerations

I want to implement more features as to extend the markdown specification, and in this link, you can see the following considerations to be made for future feature implementations.

If you want to help, check the TODO of the developer and the contribution guidelines.

Contributions

For the contribution guidelines, visit this link.

For contributing in the latest version of md2pdf, visit this link

License

MIT

Copyright for portions of project md2pdf are held by [Julien Maupetit, Github account jmaupetit owner, 2016-2021] as part of project md2pdf, by [c4ffein, Github account c4ffein owner, 2021-2022] as part of project txt2pdf, by [Simon Sapin, Github account SimonSapin owner, 2011-2023] as part of project WeasyPrint, by [Pallets, Github account pallets owner, 2014-2022] as part of project click, by [mbarkhau, Github account mbarkhau owner, 2019-2021] as part of project markdown-katex, by [Python-Markdown, Github account Python-Markdown owner, 2007-2023] as part of project markdown, by [whi_ne, Github account whinee owner, 2021-2022] as part of project MangDL, and by [whi_ne, Github account whinee owner, 2022] as part of project YAMHL.

All other copyright for project md2pdf are held by [Github Account whinee Owner, 2023].

Check the LICENSE for more details.

Attribution

Massachusetts Institute of Technology (vectorized by Mysid, modified by whinee), Public domain, via Wikimedia Commons

Icons

Exclamation Mark, Code Fork, Star, Group, Code, and Discord icons by Icons8

NOTE: If a reference or source material is not attributed properly or not at all, please kindly message me at Discord: whi_ne#4783 or create a pull request so I can properly give credit to their respective authors.

Further Reading

\ No newline at end of file + md2pdf

md2pdf

Markdown to PDF converter

wakatime Codacy Badge GitHub release (latest by date including pre-releases) GitHub Workflow Status


For writing faster? No. For writing with *class*? Yusss


Github: github.com/whinee/md2pdf

Website: m2p.whinyaan.xyz


To be updated, be sure to watch this repository and join the Discord Support Server for this and other projects.

Interested in commissioning projects? Inquire through Discord(whi_ne#4783) or through e-mail(whinyaan@protonmail.com). Price starts at 30 USD.

Important

md2pdf is still in Unreleased Alpha Development Stage.

Using the program at this stage is not recommended.

Downloads

Since people are looking for the download first, here you go:

Follow this link to install md2pdf in your machine.

What’s this?

md2pdf is a Markdown to PDF converter that can also do a lot of stuff:

  • Headers and Footers
    • Can be in Markdown or HTML format
    • Support for first page header and footer
  • Print output HTML
  • Programmatic Usage

Supported OSes

  • Windows
  • MacOS
  • Linux

Usage

This section is not yet complete.

Getting Started

The instructions will get you a copy of the project up and running on your local machine for development and testing purposes., visit this link

Advantages

  • Standardized Styles
  • Consistent Results
  • Programmatic Usage

Disadvantages

  • This program does not guarantee that you will be able to write faster, just be able to write in markdown (effectively plaintext) and produce consistent results (assuming that you use the same text, settings, stylesheet/s, and whatnot)
  • Have to link pictures online in order to attach one in the document, unlike in fancy word editors like Microsoft Word or LibreOffice Writer

Translations

This program is translation (i18n) ready!

Please refer to this link to learn more on how to create a translation for this program.

Known Issues and Limitations

  • This program can not be run in termux due to an inherent bug in AOSP that the said org's developers refuses to fix even if it will only take (apparently) a change in a single line of code (I forgot where the relevant Stackoverflow link is stored at, nor do I know the keywords for searching it up)

Considerations

I want to implement more features as to extend the markdown specification, and in this link, you can see the following considerations to be made for future feature implementations.

If you want to help, check the TODO of the developer and the contribution guidelines.

Contributions

For the contribution guidelines, visit this link.

For contributing in the latest version of md2pdf, visit this link

License

MIT

Copyright for portions of project md2pdf are held by [Julien Maupetit, Github account jmaupetit owner, 2016-2021] as part of project md2pdf, by [c4ffein, Github account c4ffein owner, 2021-2022] as part of project txt2pdf, by [Simon Sapin, Github account SimonSapin owner, 2011-2023] as part of project WeasyPrint, by [Pallets, Github account pallets owner, 2014-2022] as part of project click, by [mbarkhau, Github account mbarkhau owner, 2019-2021] as part of project markdown-katex, by [Python-Markdown, Github account Python-Markdown owner, 2007-2023] as part of project markdown, by [whi_ne, Github account whinee owner, 2021-2022] as part of project MangDL, and by [whi_ne, Github account whinee owner, 2022] as part of project YAMHL.

All other copyright for project md2pdf are held by [Github Account whinee Owner, 2023].

Check the LICENSE for more details.

Attribution

Massachusetts Institute of Technology (vectorized by Mysid, modified by whinee), Public domain, via Wikimedia Commons

Icons

Exclamation Mark, Code Fork, Star, Group, Code, and Discord icons by Icons8

NOTE: If a reference or source material is not attributed properly or not at all, please kindly message me at Discord: whi_ne#4783 or create a pull request so I can properly give credit to their respective authors.

Further Reading

\ No newline at end of file diff --git a/dev/site/latest-bump/index.html b/dev/site/latest-bump/index.html index 7a8a271..6ef2359 100644 --- a/dev/site/latest-bump/index.html +++ b/dev/site/latest-bump/index.html @@ -1 +1 @@ - Latest bump - md2pdf
\ No newline at end of file + Latest bump - md2pdf
\ No newline at end of file diff --git a/dev/site/latest-commit/index.html b/dev/site/latest-commit/index.html index b036837..a01b322 100644 --- a/dev/site/latest-commit/index.html +++ b/dev/site/latest-commit/index.html @@ -1 +1 @@ - Latest commit - md2pdf
\ No newline at end of file + Latest commit - md2pdf
\ No newline at end of file diff --git a/dev/site/latest-release-notes/index.html b/dev/site/latest-release-notes/index.html index 5957b3f..aeed964 100644 --- a/dev/site/latest-release-notes/index.html +++ b/dev/site/latest-release-notes/index.html @@ -1 +1 @@ - Latest release notes - md2pdf
\ No newline at end of file + Latest release notes - md2pdf
\ No newline at end of file diff --git a/dev/site/license/index.html b/dev/site/license/index.html index 31fe259..e932d38 100644 --- a/dev/site/license/index.html +++ b/dev/site/license/index.html @@ -1 +1 @@ - License - md2pdf

MIT LICENSE

Copyright for portions of project md2pdf are held by [Julien Maupetit, Github account jmaupetit owner, 2016-2021] as part of project md2pdf, by [c4ffein, Github account c4ffein owner, 2021-2022] as part of project txt2pdf, by [Simon Sapin, Github account SimonSapin owner, 2011-2023] as part of project WeasyPrint, by [Pallets, Github account pallets owner, 2014-2022] as part of project click, by [mbarkhau, Github account mbarkhau owner, 2019-2021] as part of project markdown-katex, by [Python-Markdown, Github account Python-Markdown owner, 2007-2023] as part of project markdown, by [whi_ne, Github account whinee owner, 2021-2022] as part of project MangDL, and by [whi_ne, Github account whinee owner, 2022] as part of project YAMHL.

All other copyright for project md2pdf are held by [Github Account whinee Owner, 2023].

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

\ No newline at end of file + License - md2pdf

MIT LICENSE

Copyright for portions of project md2pdf are held by [Julien Maupetit, Github account jmaupetit owner, 2016-2021] as part of project md2pdf, by [c4ffein, Github account c4ffein owner, 2021-2022] as part of project txt2pdf, by [Simon Sapin, Github account SimonSapin owner, 2011-2023] as part of project WeasyPrint, by [Pallets, Github account pallets owner, 2014-2022] as part of project click, by [mbarkhau, Github account mbarkhau owner, 2019-2021] as part of project markdown-katex, by [Python-Markdown, Github account Python-Markdown owner, 2007-2023] as part of project markdown, by [whi_ne, Github account whinee owner, 2021-2022] as part of project MangDL, and by [whi_ne, Github account whinee owner, 2022] as part of project YAMHL.

All other copyright for project md2pdf are held by [Github Account whinee Owner, 2023].

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

\ No newline at end of file diff --git a/dev/site/notes-to-self/index.html b/dev/site/notes-to-self/index.html index 2b7a60b..bafe38d 100644 --- a/dev/site/notes-to-self/index.html +++ b/dev/site/notes-to-self/index.html @@ -1,4 +1,4 @@ - Notes to self - md2pdf

Notes to Self

Look, whi_ne, I have written this for you.

Please, do I humbly plead you, do not ever forgot to read this before pushing changes to Github.

Versioning System

Look, you have made your own versioning system based off semver 2.0.0. Use it properly.

Given a version number user.dev.minor.patch, increment the:

  • user version when you make any changes to the user interface/experience. This does not include improvements on loading times, despite being well within the user experience umbrella.
  • dev version when you make incompatible API changes,
  • minor version when you add functionality in a backwards compatible manner, and
  • patch version when you make backwards compatible bug fixes.

If in doubt, please DO visit semver.org.

Version Bump Guides

  • ANY change in the user interface/experience SHALL induce a user version bump.
  • ANY change in the schema shall induce a dev version bump.
  • ANY change in the documentation SHALL NOT induce any version bump.
flowchart TD
+ Notes to self - md2pdf        
         
       

Notes to Self

Look, whi_ne, I have written this for you.

Please, do I humbly plead you, do not ever forgot to read this before pushing changes to Github.

Versioning System

Look, you have made your own versioning system based off semver 2.0.0. Use it properly.

Given a version number user.dev.minor.patch, increment the:

  • user version when you make any changes to the user interface/experience. This does not include improvements on loading times, despite being well within the user experience umbrella.
  • dev version when you make incompatible API changes,
  • minor version when you add functionality in a backwards compatible manner, and
  • patch version when you make backwards compatible bug fixes.

If in doubt, please DO visit semver.org.

Version Bump Guides

  • ANY change in the user interface/experience SHALL induce a user version bump.
  • ANY change in the schema shall induce a dev version bump.
  • ANY change in the documentation SHALL NOT induce any version bump.
flowchart TD
     VB([Version Bump])
         VB --> |"prerelease identifier (pi)"| e_pr{existing `pi`}
             e_pr --> |none| bprv("bump prerelease version (pv)")
@@ -23,4 +23,4 @@
 ### Security
 
 - Fixed stuff where the anilist token is leaked to everyone using this app.
-

Documentation

The documentation system is a custom solution.

If the documentation generator fails, check the traceback. It is commonly due to errors in the code and not the generator itself.

Do not blame the shitty generator you wrote. You might just have written a faulty code.

\ No newline at end of file +

Documentation

The documentation system is a custom solution.

If the documentation generator fails, check the traceback. It is commonly due to errors in the code and not the generator itself.

Do not blame the shitty generator you wrote. You might just have written a faulty code.

\ No newline at end of file diff --git a/dev/site/search/search_index.json b/dev/site/search/search_index.json index 936453d..92a9e59 100644 --- a/dev/site/search/search_index.json +++ b/dev/site/search/search_index.json @@ -1 +1 @@ -{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Home","text":"md2pdf Markdown to PDF converter For writing faster? No. For writing with *class*? Yusss

Github: github.com/whinee/md2pdf

Website: m2p.whinyaan.xyz

To be updated, be sure to watch this repository and join the Discord Support Server for this and other projects.

Interested in commissioning projects? Inquire through Discord(whi_ne#4783) or through e-mail(whinyaan@protonmail.com). Price starts at 30 USD.

"},{"location":"#toc","title":"Table of Contents","text":"
  • Important
  • Downloads
  • What\u2019s this?
    • Supported OSes
  • Usage
  • Getting Started
  • Advantages
  • Disadvantages
  • Translations
  • Known Issues and Limitations
  • Considerations
  • Contributions
  • License
    • MIT
  • Attribution
    • MIT Logo
    • Icons
  • Further Reading
"},{"location":"#important","title":"Important","text":"

md2pdf is still in Unreleased Alpha Development Stage.

Using the program at this stage is not recommended.

"},{"location":"#downloads","title":"Downloads","text":"

Since people are looking for the download first, here you go:

Follow this link to install md2pdf in your machine.

"},{"location":"#what-s-this","title":"What\u2019s this?","text":"

md2pdf is a Markdown to PDF converter that can also do a lot of stuff:

  • Headers and Footers
    • Can be in Markdown or HTML format
    • Support for first page header and footer
  • Print output HTML
  • Programmatic Usage
"},{"location":"#what-s-this-supported-oses","title":"Supported OSes","text":"
  • Windows
  • MacOS
  • Linux
"},{"location":"#usage","title":"Usage","text":"

This section is not yet complete.

"},{"location":"#getting-started","title":"Getting Started","text":"

The instructions will get you a copy of the project up and running on your local machine for development and testing purposes., visit this link

"},{"location":"#advantages","title":"Advantages","text":"
  • Standardized Styles
  • Consistent Results
  • Programmatic Usage
"},{"location":"#disadvantages","title":"Disadvantages","text":"
  • This program does not guarantee that you will be able to write faster, just be able to write in markdown (effectively plaintext) and produce consistent results (assuming that you use the same text, settings, stylesheet/s, and whatnot)
  • Have to link pictures online in order to attach one in the document, unlike in fancy word editors like Microsoft Word or LibreOffice Writer
"},{"location":"#translations","title":"Translations","text":"

This program is translation (i18n) ready!

Please refer to this link to learn more on how to create a translation for this program.

"},{"location":"#known-issues-and-limitations","title":"Known Issues and Limitations","text":"
  • This program can not be run in termux due to an inherent bug in AOSP that the said org's developers refuses to fix even if it will only take (apparently) a change in a single line of code (I forgot where the relevant Stackoverflow link is stored at, nor do I know the keywords for searching it up)
"},{"location":"#considerations","title":"Considerations","text":"

I want to implement more features as to extend the markdown specification, and in this link, you can see the following considerations to be made for future feature implementations.

If you want to help, check the TODO of the developer and the contribution guidelines.

"},{"location":"#contributions","title":"Contributions","text":"

For the contribution guidelines, visit this link.

For contributing in the latest version of md2pdf, visit this link

"},{"location":"#license","title":"License","text":""},{"location":"#mit","title":"MIT","text":"

Copyright for portions of project md2pdf are held by [Julien Maupetit, Github account jmaupetit owner, 2016-2021] as part of project md2pdf, by [c4ffein, Github account c4ffein owner, 2021-2022] as part of project txt2pdf, by [Simon Sapin, Github account SimonSapin owner, 2011-2023] as part of project WeasyPrint, by [Pallets, Github account pallets owner, 2014-2022] as part of project click, by [mbarkhau, Github account mbarkhau owner, 2019-2021] as part of project markdown-katex, by [Python-Markdown, Github account Python-Markdown owner, 2007-2023] as part of project markdown, by [whi_ne, Github account whinee owner, 2021-2022] as part of project MangDL, and by [whi_ne, Github account whinee owner, 2022] as part of project YAMHL.

All other copyright for project md2pdf are held by [Github Account whinee Owner, 2023].

Check the LICENSE for more details.

"},{"location":"#attribution","title":"Attribution","text":""},{"location":"#attribution-mit-logo","title":"MIT Logo","text":"

Massachusetts Institute of Technology (vectorized by Mysid, modified by whinee), Public domain, via Wikimedia Commons

"},{"location":"#attribution-icons","title":"Icons","text":"

Exclamation Mark, Code Fork, Star, Group, Code, and Discord icons by Icons8

NOTE: If a reference or source material is not attributed properly or not at all, please kindly message me at Discord: whi_ne#4783 or create a pull request so I can properly give credit to their respective authors.

"},{"location":"#further-reading","title":"Further Reading","text":"
  • Frequently Asked Questions
  • License Agreement
  • Latest Documentation (0.0.x.x)
  • All Documentation
  • Changelog
  • Latest Bump
  • Latest Commit
  • Notes for whi~nyaan!
  • whi~nyaan!'s diary
"},{"location":"TODO/","title":"TODO","text":""},{"location":"TODO/#toc","title":"Table of Contents","text":"
  • Todo
  • In Progress
  • Done
"},{"location":"TODO/#todo","title":"Todo","text":"
  • [ ] n-column support
  • [ ] GUI
  • [ ] Custom Help Function (to only compute help page's width when help is actually called; the CLI is actually already fast enough that this might not be necessary, but is just a mere novelty)
"},{"location":"TODO/#in-progress","title":"In Progress","text":"
  • [ ] Custom mermaid.js renderer (will be done after the GUI, as the HUI will be written in JS, and the rendered will be using JS too)
"},{"location":"TODO/#done","title":"Done","text":"
  • [x] Custom KaTex renderer (as the best one for Weasyprint use, mbarkhau/markdown-katex is so dang slow)
"},{"location":"changelog/","title":"Changelog","text":"Changelog"},{"location":"changelog/#0-0-0-0-0-0","title":"0.0.0.0-alpha.0","text":""},{"location":"considerations/","title":"Considerations","text":"Considerations for Future Feature Implementation"},{"location":"considerations/#toc","title":"Table of Contents","text":"
  • Page Breaks
  • Columns
  • GUI
"},{"location":"considerations/#page-breaks","title":"Page Breaks","text":"

There is no plain markdown way to add pagebreak in a markdown file. However, I came across this stackoverflow answer that mentions that the answer-er uses <<<<>>>> to denote pagebreak in their documents. And I liked that! And as such, I think I will implement just that in later versions of this program.

"},{"location":"considerations/#columns","title":"Columns","text":"

Before this project can even convert markdown to PDF files in sub-ten seconds, I have been using tables as substitute for columns. This is as the Commonmark Markdown specification does not support such feature.

However, there is a simple problem with tables in markdown: it does not support multi-line cells

Time and time again, I have searched for ways to be able to write multi-line cells in a kind of markdown way. All of them are ugly implementations. None of them can satisfy me.

And then I came across MultiMarkdown's table documentation which makes an interesting observation:

If you need complex tables you will need to create them by hand or with a tool specifically designed for your output format. At some point, however, you should consider whether a table is really the best approach if you find MultiMarkdown tables too limiting.

And I think that that is true.

However, I have thought of a solution. That is to parse markdown inside HTML tags. Such as that the following markdown...

<table>\n    <tr>\n        <th>Header</th>\n    </tr>\n    <tr>\n        <td>\n            - Lorem ipsum dolor sit amet\n            - Consectetur adipiscing elit\n            - Integer molestie lorem at massa\n        </td>\n    </tr>\n</table>\n

...will be converted to HTML like the following:

<table>\n    <tr>\n        <th>Header</th>\n    </tr>\n    <tr>\n        <td>\n            <ul>\n                <li>Lorem ipsum dolor sit amet</li>\n                <li>Consectetur adipiscing elit</li>\n                <li>Integer molestie lorem at massa</li>\n            </ul>\n        </td>\n    </tr>\n</table>\n

But, I think that the best solution would be to just make my own implementation of columns.

A solution I am considering at the time of writing is using a custom HTML tag called cols (stands for columns) that wraps col (stands for column) tags, which in turn wraps content in a column. Such as that the following markdown leads to 3 columns.

<cols>\n    <col>\n        Column #1\n    </col>\n    <col>\n        Column #2\n    </col>\n    <col>\n        Column #3\n    </col>\n</cols>\n

And yes, the content inside each col tags will be interpreted as markdown.

"},{"location":"considerations/#gui","title":"GUI","text":"

I do not have proper plans for the GUI of this project yet. But boredom does wonders.

I was once subjected to the horrors of national achievement test and mock exams for 4 days. And we are not allowed to use our phones for 4-5 hours straight a day, for 4 days. And so, I scribbled to a scratch paper that I had. And what do you know, I have this graph.

A week later, I graphed the thing in mermaid.js, and here it is:

sequenceDiagram\n    participant A as core.py\n    participant B as main.js\n    participant C as renderer.js\n\n    Note over A,C: Initialize\n\n    B -) C: Run\n    note left of C: show loading screen\n    B -) A: Run\n    alt log path is `None`\n        A ->> B: request Electron.js App Directory\n        note left of B: get Electron.js App Directory\n        B --) A: Electron.js App Directory\n    end\n\n    A ->> B: log path\n    C ->> B: ready\n    B ->> C: tx log path\n    note left of C: console.log(log path)\n    C ->> B: ack\n    B ->> A: tx ack\n    A ->> B: cfg\n    note left of B: process cfg\n    B ->> C: tx cfg\n    note left of C: remove loading screen\n\n    Note over A,C: Nominal Operation\n\n    alt log\n        B -) A: log\n        note right of A: log\n    end\n\n    alt log\n        C -)+ B: log\n        B -)- A: tx log\n        note right of A: log\n    end\n\n    alt mod cfg\n        B -) A: mod cfg\n        note right of A: rewrite cfg\n    end\n\n    alt mod cfg\n        C -)+ B: mod cfg\n        B -)- A: tx mod cfg\n        note right of A: rewrite cfg\n    end\n\n    alt ctl\n        B -) A: ctl\n        note right of A: process\n        alt res\n            A --) B: res\n            alt tx res\n                B --) C: tx res\n            end\n        end\n    end\n\n    alt ctl\n        C -) B: ctl\n        B -) A: tx ctl\n        note right of A: process\n        alt res\n            A --) B: res\n            alt tx res\n                B --) C: tx res\n            end\n        end\n    end
"},{"location":"contributing/","title":"Contributing","text":"Contributing to md2pdf

First off, thanks for taking the time to contribute! \u2764\ufe0f

All types of contributions are encouraged and valued. See the Table of Contents for different ways to help and details about how this project handles them. Please make sure to read the relevant section before making your contribution. It will make it a lot easier for us maintainers and smooth out the experience for all involved. The community looks forward to your contributions. \ud83c\udf89

And if you like the project, but just don't have time to contribute, that's fine. There are other easy ways to support the project and show your appreciation, which we would also be very happy about: - Star the project - Tweet about it - Refer this project in your project's README - Mention the project at local meetups and tell your friends/colleagues

"},{"location":"contributing/#toc","title":"Table of Contents","text":"
  • Code of Conduct
  • I Have a Question
  • I Want To Contribute
    • Legal Notice
    • Reporting Bugs
      • Before Submitting a Bug Report
      • How Do I Submit a Good Bug Report?
    • Suggesting Enhancements
      • Before Submitting an Enhancement
      • How Do I Submit a Good Enhancement Suggestion?
    • Your First Code Contribution
    • Improving The Documentation
  • Submitting a Pull Request
    • Dont\u2019s
  • Style guides
    • Commit Messages
    • Code
  • Join The Project Team
  • Attribution
"},{"location":"contributing/#code-of-conduct","title":"Code of Conduct","text":"

This project and everyone participating in it is governed by the md2pdf Code of Conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to <>.

"},{"location":"contributing/#i-have-a-question","title":"I Have a Question","text":"

If you want to ask a question, we assume that you have read the available Latest Documentation (0.0.x.x).

Before you ask a question, it is best to search for existing Issues that might help you. In case you have found a suitable issue and still need clarification, you can write your question in this issue. It is also advisable to search the internet for answers first.

If you then still feel the need to ask a question and need clarification, we recommend the following:

  • Open an Issue.
  • Provide as much context as you can about what you're running into.
  • Provide the following information:
    • OS name and version If in Linux, include linux distribution and kernel version; and
    • Python version

We will then take care of the issue as soon as possible.

"},{"location":"contributing/#i-want-to-contribute","title":"I Want To Contribute","text":""},{"location":"contributing/#i-want-to-contribute-legal-notice","title":"Legal Notice","text":"When contributing to this project, you must agree that you have authored 100% of the content, that you have the necessary rights to the content and that the content you contribute may be provided under the project license."},{"location":"contributing/#i-want-to-contribute-reporting-bugs","title":"Reporting Bugs","text":""},{"location":"contributing/#i-want-to-contribute-reporting-bugs-before-submitting-a-bug-report","title":"Before Submitting a Bug Report","text":"

A good bug report shouldn't leave others needing to chase you up for more information. Therefore, we ask you to investigate carefully, collect information and describe the issue in detail in your report. Please complete the following steps in advance to help us fix any potential bug as fast as possible.

  • Make sure that you are using the latest version.
  • Determine if your bug is really a bug and not an error on your side e.g. using incompatible environment components/versions (Make sure that you have read the Latest Documentation (0.0.x.x). If you are looking for support, you might want to check this section).
  • To see if other users have experienced (and potentially already solved) the same issue you are having, check if there is not already a bug report existing for your bug or error in the bug tracker.
  • Also make sure to search the internet (including Stack Overflow) to see if users outside of the GitHub community have discussed the issue.

  • Collect information about the bug

  • Stack trace (Traceback)
  • OS, Platform and Version (Windows, Linux, macOS, x86, ARM)
  • Version of the interpreter, compiler, SDK, runtime environment, package manager, depending on what seems relevant.
  • Possibly your input and the output
  • Can you reliably reproduce the issue? And can you also reproduce it with older versions?
"},{"location":"contributing/#i-want-to-contribute-reporting-bugs-how-do-i-submit-a-good-bug-report","title":"How Do I Submit a Good Bug Report?","text":"

You must never report security related issues, vulnerabilities or bugs including sensitive information to the issue tracker, or elsewhere in public. Instead sensitive bugs must be sent by email to <>.

We use GitHub issues to track bugs and errors. If you run into an issue with the project:

  • Open an Issue. (Since we can't be sure at this point whether it is a bug or not, we ask you not to talk about a bug yet and not to label the issue.)
  • Explain the behavior you would expect and the actual behavior.
  • Please provide as much context as possible and describe the reproduction steps that someone else can follow to recreate the issue on their own. This usually includes your code. For good bug reports you should isolate the problem and create a reduced test case.
  • Provide the information you collected in the previous section.

Once it's filed:

  • The project team will label the issue accordingly.
  • A team member will try to reproduce the issue with your provided steps. If there are no reproduction steps or no obvious way to reproduce the issue, the team will ask you for those steps and mark the issue as needs-repro. Bugs with the needs-repro tag will not be addressed until they are reproduced.
  • If the team is able to reproduce the issue, it will be marked needs-fix, as well as possibly other tags (such as critical), and the issue will be left to be implemented by someone.
"},{"location":"contributing/#i-want-to-contribute-suggesting-enhancements","title":"Suggesting Enhancements","text":"

This section guides you through submitting an enhancement suggestion for md2pdf, including completely new features and minor improvements to existing functionality. Following these guidelines will help maintainers and the community to understand your suggestion and find related suggestions.

"},{"location":"contributing/#i-want-to-contribute-suggesting-enhancements-before-submitting-an-enhancement","title":"Before Submitting an Enhancement","text":"
  • Make sure that you are using the latest version.
  • Read the Latest Documentation (0.0.x.x) carefully and find out if the functionality is already covered, maybe by an individual configuration.
  • Perform a search to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one.
  • Find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the project's developers of the merits of this feature. Keep in mind that we want features that will be useful to the majority of our users and not just a small subset. If you're just targeting a minority of users, consider writing an add-on/plugin library.
"},{"location":"contributing/#i-want-to-contribute-suggesting-enhancements-how-do-i-submit-a-good-enhancement-suggestion","title":"How Do I Submit a Good Enhancement Suggestion?","text":"

Enhancement suggestions are tracked as GitHub issues.

  • Use a clear and descriptive title for the issue to identify the suggestion.
  • Provide a step-by-step description of the suggested enhancement in as many details as possible.
  • Describe the current behavior and explain which behavior you expected to see instead and why. At this point you can also tell which alternatives do not work for you.
  • You may want to include screenshots and animated GIFs which help you demonstrate the steps or point out the part which the suggestion is related to. You can use this tool to record GIFs on macOS and Windows, and this tool or this tool on Linux.
  • Explain why this enhancement would be useful to most md2pdf users. You may also want to point out the other projects that solved it better and which could serve as inspiration.
"},{"location":"contributing/#i-want-to-contribute-your-first-code-contribution","title":"Your First Code Contribution","text":""},{"location":"contributing/#i-want-to-contribute-improving-the-documentation","title":"Improving The Documentation","text":""},{"location":"contributing/#submitting-a-pull-request","title":"Submitting a Pull Request","text":"

This is based on Michael Herrmann's gist titled Good PRs are minimal.

Every Pull Request (hereinafter referred to as PR) should have one, and only one, unique goal. The PR should make the absolute minimum number of changes that are required to achieve this goal.

The fewer things you change, the easier it will be for the team to see what you did, and thus gain confidence that you PR makes sense.

"},{"location":"contributing/#submitting-a-pull-request-dont-s","title":"Dont\u2019s","text":"
  • Changing whitespace unnecessarily, eg. switching tabs and spaces.

    This leads to huge numbers of unnecessarily changed lines of code.

  • Running a linter not listed in the linters currently used by the project

  • Don't unnecessarily introduce new tools or dependencies. I'm sure you have your favorites. But don't force them on me or other contributors. Stick to those that are absolutely required, or come with the language.
  • Obey the same code style as the library: Tabs or spaces, maximum line length, etc.

In short: Good PRs are minimal. You're very welcome to add several improvements. But please make them in separate PRs.

"},{"location":"contributing/#style-guides","title":"Style guides","text":""},{"location":"contributing/#style-guides-commit-messages","title":"Commit Messages","text":"

This repository does not enforce a style guide on commits. However, it is highly recommended to be concise and informative when writing commit messages.

"},{"location":"contributing/#style-guides-code","title":"Code","text":"

This project uses the following linters for the

"},{"location":"contributing/#join-the-project-team","title":"Join The Project Team","text":""},{"location":"contributing/#attribution","title":"Attribution","text":"

This guide is based on the contributing-gen. Make your own!

"},{"location":"diary/","title":"Diary","text":"r/offmychest

Written below are rants and lessons I have learned in making this project, and whatnot. Basically, I do not know, I just want to get it out of my chest.

"},{"location":"diary/#toc","title":"Table of Contents","text":"
  • KaTeX Support
"},{"location":"diary/#katex-support","title":"KaTeX Support","text":"

For this project, I planned it to ship with a KaTeX support.

I have only found a single python-markdown extension that is also compatible with Weasyprint, and that is markdown-katex by mbarkhau. However, it is so dang slow.

From my testing, it takes about 200 seconds (or roughly over 3 mins) to convert a markdown file with around 5-10 formulae in it to a 200 kb PDF file, which is about a kbps. However, that is a shitty metric, as there is an image in there, but you get the point, It is slow as fuck.

Now, what I did is attempt to rewrite mbarkhau's implementation of KaTeX for python-markdown. Built it from the ground up, taking motivation from the original project and some other extensions along the way. Heavily rebuilding the logic behind the things that I figured out takes up most of the time.

I narrowed it down to two things that slows it down the most: the preprocessor and postprocessor functions. I figured out that the iterator for feeding KaTeX formulae into the KaTeX binary took the longest as the process persists for quite a while on my machine's process monitoring tool. And as such, I made that process multithreaded.

Weeks after almost achieving feature-parity with the original project, I encountered an error. It was not of my program, but of the python-markdown's. And as such, I dug up the code that caused that error and extracted that to my program to be able to modify the code and remove the snippet that causes the error in the first place. And of course, that affected the rendering process.

There's no more hope. I did something wrong, and I can not track down where it went wrong.

Then, it finally hit me. The problem is when I attempted to rebuild the already perfect python-markdown KaTeX implementation. I just need to make it multithreaded. And while I still need to extract the stuff to make it work with the other stuff that I plan to add, I still only need to modify about 20% of the original project. I am so fucking dumb.

Or so I thought, two weeks later, after doing just that, it's still slow. And what I mean by slow is that I can run the program, wash the plate I used for eating the leftover cake for like about a minute or two, make myself a cup of coffee, and come back to that damn thing still running! Luckily, I narrowed it down to the very root cause of it all: the logic that searches for the KaTeX binary in the machine.

I do not know how or why the heck is it so slow. In any case, I replaced it with a shutil's implementation of which, modified to work with the extension. And fortunately, it worked! The logic still looks the same as the old one, but the damn thing runs from 30 secs down to sub-five seconds, depending where the binary is at. Like, whaaaaaat?!?!

What is the moral of the story then? That someone's code might actually be the best solution for the problem. But if it does not work, then do not try to rebuild it from the ground up. See first if you can modify some parts of it to work with your problem. Then if it does not work, then proceed to rebuilding it. As often times, that solution might be the best solution for that exact problem, but not for your own, exact problem.

Or is that it?

Maybe I just wanted to rant about the stupid weeks I have wasted for this little thing to fucking work? Or is it because I just wanted to flex how much I have optimized a single thing?

I do not fucking know, but I sure did flex'd to my friends about how I \"optimized\" a program to run 40x faster. I mean, where is the lie?

Now, where am I again? Oh, right, KaTeX support. Yay, finally added! UwU

"},{"location":"faq/","title":"Faq","text":"FAQ"},{"location":"faq/#toc","title":"Table of Contents","text":"
  • Is this application safe?
  • What are your intentions in making this application?
  • Who are you?
"},{"location":"faq/#is-this-application-safe","title":"Is this application safe?","text":"TL;DR: First of all, safe from what aspect, bruv? Considering that you are asking this, probably not. Is this application safe for my computer? TL;DR: Yes, but not really. Safe enough to put a 99.99% safety guarantee on it, air commercials of it, and not get sued on the grounds of false advertisement.

No software is ever safe, and there will never be. Unless if we, for some mysterious and divine reason, gain the ability to prove if a program halts or not, which in this universe is impossible (relevant link: Halting problem).

Enough of explaining the philosophical implications of this problematic question, and let us go to the real meat of the discussion. No, I can not assure you, as the developer of this application, that this application is safe. It is like asking if I poisoned your food; regardless of if I did it or not, I will dutifully deny the allegation, duh. Inquired you did, now trust me. Make of that what you will, but I am here to chase clout and make money out of it, not to compromise machines.

Well, with all that said, I also made it for personal use. And for that, I have to make it at the very least usable to the extent that it would not compromise the host machine that it is running on.

Don't trust me? The application is open-sourced. Every packaged application downloaded from the official site and Github repository is built from the same source as available on the official Github repository. If you know how to read the source code, you are free to do so, and inspect it. If you did do so, please hunt down some bugs for me. Much appreciated UwU

To end this answer, well... I mean, you could run the thing on a virus checker. Although, what might be an innocuous yet insecure system API call might be flagged as a suspicious activity. Not that I am aware of anything of that sort in my application, but I think that that will suffice as an example.

"},{"location":"faq/#what-are-your-intentions-in-making-this-application","title":"What are your intentions in making this application?","text":"TL;DR: It's a hobby of mine. It is not driven by money or ill intentions. Inquired you did, now trust me.

This started out as a hobby project. To pass time, and live out the rest of my days as a virgin NEET and a total social recluse. Assuming that you can see this site right now, it has grew into this large and popular project that it has become.

My intentions however are still the same as it was months ago. However, I have a side goal in mind right now: to attain popularity in the open source scene, enough to get me enough freelancing work and earn money.

Yes, that is it, really. I am in it for the money, but the development of this application is but money-driven. I mean, I would very much appreciate it if you could donate money or a little bit of your time to this little endeavour of mine, or commission me to do some work for you.

"},{"location":"faq/#who-are-you","title":"Who are you?","text":"TL;DR: That's a creepy thing to ask dude, I'm a teenager. \\s

Hello, I am whi_ne, short for whitespace_negative. 17 at the time of writing. I am a python and a web developer, albeit shitty at both of them. I also do some freelance work. Nice to meet ya!

Yes, I use an alias; personal branding is dead. I also want to stay anonymous. However, my pics on multiple guys' DMs suggests otherwise. And yes, please do not dig up dirt on me, I will let you know everything there is to know about me.

"},{"location":"latest-bump/","title":"Latest bump","text":"Latest Version Bump"},{"location":"latest-bump/#0000-alpha0","title":"0.0.0.0-alpha.0","text":"

<font color=\""},{"location":"latest-commit/","title":"Latest commit","text":"Latest Commit"},{"location":"latest-commit/#summary","title":"Summary","text":"

Yet 'nother fucking oopsies...

"},{"location":"latest-commit/#changes","title":"Changes","text":""},{"location":"latest-release-notes/","title":"Latest release notes","text":"0.0.0.0-alpha.0"},{"location":"latest-release-notes/#description","title":"Description","text":"

<font color=\""},{"location":"license/","title":"License","text":"MIT LICENSE

Copyright for portions of project md2pdf are held by [Julien Maupetit, Github account jmaupetit owner, 2016-2021] as part of project md2pdf, by [c4ffein, Github account c4ffein owner, 2021-2022] as part of project txt2pdf, by [Simon Sapin, Github account SimonSapin owner, 2011-2023] as part of project WeasyPrint, by [Pallets, Github account pallets owner, 2014-2022] as part of project click, by [mbarkhau, Github account mbarkhau owner, 2019-2021] as part of project markdown-katex, by [Python-Markdown, Github account Python-Markdown owner, 2007-2023] as part of project markdown, by [whi_ne, Github account whinee owner, 2021-2022] as part of project MangDL, and by [whi_ne, Github account whinee owner, 2022] as part of project YAMHL.

All other copyright for project md2pdf are held by [Github Account whinee Owner, 2023].

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

"},{"location":"notes-to-self/","title":"Notes to self","text":"Notes to Self

Look, whi_ne, I have written this for you.

Please, do I humbly plead you, do not ever forgot to read this before pushing changes to Github.

"},{"location":"notes-to-self/#toc","title":"Table of Contents","text":"
  • Versioning System
    • Version Bump Guides
  • Changelog
  • Documentation
"},{"location":"notes-to-self/#versioning-system","title":"Versioning System","text":"

Look, you have made your own versioning system based off semver 2.0.0. Use it properly.

Given a version number user.dev.minor.patch, increment the:

  • user version when you make any changes to the user interface/experience. This does not include improvements on loading times, despite being well within the user experience umbrella.
  • dev version when you make incompatible API changes,
  • minor version when you add functionality in a backwards compatible manner, and
  • patch version when you make backwards compatible bug fixes.

If in doubt, please DO visit semver.org.

"},{"location":"notes-to-self/#versioning-system-version-bump-guides","title":"Version Bump Guides","text":"
  • ANY change in the user interface/experience SHALL induce a user version bump.
  • ANY change in the schema shall induce a dev version bump.
  • ANY change in the documentation SHALL NOT induce any version bump.
flowchart TD\n    VB([Version Bump])\n        VB --> |\"prerelease identifier (pi)\"| e_pr{existing `pi`}\n            e_pr --> |none| bprv(\"bump prerelease version (pv)\")\n                bprv --> ba(bump `pi` to `alpha`)\n                ba --> bp([bump `patch`])\n            e_pr --> |alpha| bb(bump to `beta`)\n                bb --> r0([reset version/s below it to `0` or `none`])\n            e_pr --> |beta| br(bump to `rc`) --> r0\n            e_pr --> |rc| rn(reset to `none`) --> r0\n        VB --> |others| bsv(bump specified version) --> r0
"},{"location":"notes-to-self/#changelog","title":"Changelog","text":"

As used in the changelog, the following types of changes shall have the following implications, of which, their allowed version bumps should be everything, unless explicably stated otherwise:

  • Added for new features.
    • user
    • dev
    • minor
  • Changed for changes in existing functionality.
    • user
    • dev
  • Deprecated for soon-to-be removed features.
    • patch
  • Removed for now removed features.
    • user
    • dev
  • Fixed for any bug fixes.
  • Security in case of vulnerabilities.

Mind the human as you do with the robot. Format the changelog properly. Example format:

## 69.4.2.0 (minor bump)\n\nSprinkle a description here.\n\n### Added\n\n- I added a cool feature.\n\n### Deprecated\n\n- This feature will be deprecated 'cuz I can't maintain it anymore.\n\n### Security\n\n- Fixed stuff where the anilist token is leaked to everyone using this app.\n
"},{"location":"notes-to-self/#documentation","title":"Documentation","text":"

The documentation system is a custom solution.

If the documentation generator fails, check the traceback. It is commonly due to errors in the code and not the generator itself.

Do not blame the shitty generator you wrote. You might just have written a faulty code.

"},{"location":"terms%20of%20usage/","title":"Terms of usage","text":"Terms of Usage and Disclaimers"},{"location":"terms%20of%20usage/#toc","title":"Table of Contents","text":"
  • Defined Terms
  • Terms of Usage
  • Disclaimer
    • Revisions and Errata
    • DMCA and Copyright Infringements
    • The Developer
"},{"location":"terms%20of%20usage/#defined-terms","title":"Defined Terms","text":"

The key words \"MUST\", \"MUST NOT\", \"REQUIRED\", \"SHALL\", \"SHALL NOT\", \"SHOULD\", \"SHOULD NOT\", \"RECOMMENDED\", \"MAY\", and \"OPTIONAL\" in this document are to be interpreted as described in RFC 2119.

As used in this Disclaimer, the following terms SHALL have the following meanings (such meanings to be equally applicable to both the singular and plural forms of the terms defined unless explicably mentioned otherwise):

  • Developer hereby means the person who has developed the Project going by the alias of \"whi~nyaan!\" in the internet, username of \"whinee\" in \"Github\", username of \"whi_ne#4783\" in \"Discord\" and rightful owner of the electronic mail address \"whinyaan@protonmail.com\", only meant to be used in singular form

  • Project hereby means the Open Source Project called \"md2pdf\" developed by the Developer, only meant to be used in singular form

  • Website hereby means a set of interconnected webpages, prepared and maintained as a collection of information for the Project by the Developer, located at m2p.whinyaan.xyz, only meant to be used in singular form; and

  • User hereby means the person who uses this Project and/or Website, regardless of their intentions and attributes including, but not limited to the following:

    age, body size, caste, citizenship, civil status, disability, education, ethnicity, familial status, gender expression, gender identity, genetic information, immigration status, level of experience, nationality, personal appearance, pregnancy, race, religion, sex characteristics, sexual orientation, sexual identity, socio-economic status, tribe, and veteran status

"},{"location":"terms%20of%20usage/#terms-of-usage","title":"Terms of Usage","text":"

As stated in the license agreement, under no circumstance SHALL the Developer of this Project have any liability to the User for any loss or damage of any kind incurred as a result of the use of this Project, even if the Developer or an authorize representative of this Project and/or Website has been notified, orally or written, of the possibility of such damage including, but not limited to the following:

  • Criminal charges due to accessing illegal content where it is banned or prohibited by law; and

  • Damage to device due to usage of the Project and/or Website in said device

Some jurisdiction does not allow limitations on implied warranties or limitations of liability for incidental damages, these limitations MAY not apply to you.

The needy Developer also REQUIRES the Users to pat said developer 3 (three) times a day. Failure to do so MUST revoke the User's rights to use the app.

These Terms of Usage MAY change at any time for any and no reason and it is up to the Users to check for updates from time to time, which means that by no means SHALL the Developer be liable for the User's failure to check the Terms of Usage at a regular basis.

By using the Project and/or the Website, the User agrees and confirms to the license agreement and the Terms of Usage.

"},{"location":"terms%20of%20usage/#disclaimer","title":"Disclaimer","text":"

The Developer only intends to use this Project only for educational purposes.

"},{"location":"terms%20of%20usage/#disclaimer-revisions-and-errata","title":"Revisions and Errata","text":"

The materials and resources in this Website and the Project MAY include technical, typographical, or photographic errors. The Developer does not promise that any of the materials in this Website and the Project are accurate, complete, or current. The said Developer MAY change the materials contained on its Website at any time without notice. The Developer does not make any commitment to update the materials.

"},{"location":"terms%20of%20usage/#disclaimer-dmca-and-copyright-infringements","title":"DMCA and Copyright Infringements","text":"

The contents served by the Project is publicly accessible through the Internet. In case of copyright infringement, please direct the complaints, claims, and possible criminal charges against to the respective file hosts and content providers, not to the Project nor to the Developer, as the Developer is not affiliated with them, at any way, shape or form.

The Project is a program that serves contents like a normal browser do through scraping 3rd-party websites that are publicly accessible via any regular web browser, however it does less requests than a normal browser would, and is sophisticated enough to serve the content how the Developer would want to. It is the responsibility of the Users to avoid any actions that might violate the laws governing their locality.

"},{"location":"terms%20of%20usage/#disclaimer-the-developer","title":"The Developer","text":"

The Project is created in good faith that this will only serve an educational purpose for the Developer and the Users and will only be used for that said purpose.

By no means harassing the Developer including, but not limited to the following, is legal nor ethically and morally correct:

  • Exploiting the undisclosed personal information of the Developer against them, possibly accessed through illegal means, including, but not limited to the following:

    • Physical/Online Stalking

    • Hacking; and

    • Social Engineering

  • Sending threatening messages, mentioning doing physical harm to the Developer or not, attempts to morally degrade the said Developer, including, but not limited to the following ways:

    • Through social media platforms, including but not limited to Discord, Youtube, and Facebook

    • Through e-mail; and

    • Through physical mail

The Developer will act legally against those who have done anything illegal against the said Developer, including, but not limited to the following above.

For any concerns regarding the legality of the Project and/or Websites, begin by creating a new issue or through emailing me at whinyaan@protonmail.com or contacting me in Discord at whi_ne#4783.

"},{"location":"docs/","title":"Index","text":"All Version
  • Version 0.x.x.x
"},{"location":"docs/0/","title":"Index","text":"Version 0.x.x.x
  • Version 0.0.x.x
"},{"location":"docs/0/0/","title":"Index","text":"0.0.x.x
  • API Documentation
  • For contributors
"},{"location":"docs/0/0/installation/","title":"Installation","text":"Installating md2pdf"},{"location":"docs/0/0/installation/#toc","title":"Table of Contents","text":"
  • Windows
  • Mac
  • Linux
    • Arch
"},{"location":"docs/0/0/installation/#windows","title":"Windows","text":"
  1. Copy the following text:

    Set-ExecutionPolicy Bypass -Scope Process -Force\n[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072\niex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))\n
  2. Press Win. An interface should pop up as shown below:

  3. Search for settings by typing \"Settings\" in the text field as shown below:

    Press Enter.

  4. A window should pop up as shown below:

    Press \"Apps\" in the selection below.

  5. You should be redirected to \"Apps & Features\" as shown below:

    Below the subtitle \"Apps & Features\", press the hyperlink \"App execution aliases\".

  6. You should be redirected to \"App execution aliases\" as shown below:

    Toggle the \"App installer\" for both \"python.exe\" and \"python3.exe\". Exit the settings app.

  7. Press Windows + R (Press Windows and R keys simultaneously)

  8. A window with a title Run should appear. Focus to the said window in the Open: text field by hovering the mouse towards the said text field and left-clicking the mouse and type powershell as shown below:

  9. Press Ctrl + Shift + Enter (Press Ctrl, Shift, and Enter keys simultaneously).

  10. A window with a title User Account Control should appear as shown below:

  11. Focus to the said window and press the Yes button by hovering the mouse towards the said button and left-clicking the mouse. A window named Administrator: Windows Powershell should pop-up.

  12. Focus to the window named Administrator: Windows Powershell window by hovering the mouse towards the said window and left-clicking the mouse. Then, press Ctrl + V (Press Ctrl and V keys simultaneously).

    If the window Administrator: Windows Powershell seems to hang up, focus to said window by hovering the mouse towards the said window and left-clicking the mouse, then press Enter five times every minute or so until something happens.

  13. Restart your computer, then login to the user account to which you have done the above instructions at.

  14. Copy the following text:

    choco install nodejs -y\nnpm install katex\n
  15. Repeat step 7-12.

  16. [RECOMMENDED] Use Python environment

    It is recommended to use a Python environment to isolate the dependencies installed to the main Python installation which other programs might use, as this will reduce the chance of incompatible dependency version collisions.

    Change directory to where you want to put the Python environment, by replacing the <dir> in the following text to your desired directory in your machine, and copy the text\"

    cd <dir>\npython3 -m venv pyenv\n.\\pyenv\\Scripts\\activate\n

    Repeat step 12.

  17. Copy the following text:

    python3 -m pip install w{{pip}}\n

    And you have installed

"},{"location":"docs/0/0/installation/#mac","title":"Mac","text":"
  1. Open your preferred terminal and run the following command:

    /bin/bash -c \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)\"\n
  2. Next, for OS X 10.13 (High Sierra) or younger, run the following command:

    echo 'export PATH=\"/usr/local/opt/python/libexec/bin:$PATH\"' >> ~/.profile\n

And for OS X 10.12 (Sierra) or older, use the following command instead:

echo 'export PATH=/usr/local/bin:/usr/local/sbin:$PATH' >> ~/.profile\n

  1. Afterwards, install the rest of the prerequisites by running the following command:

    brew install node\n

  2. Then, install katex with npm by running the following command:

    npm install katex\n
"},{"location":"docs/0/0/installation/#linux","title":"Linux","text":""},{"location":"docs/0/0/installation/#linux-arch","title":"Arch","text":"
  1. Open your preferred terminal and run the following command:
    sudo pacman -Syyu --noconfirm curl\n
"},{"location":"docs/0/0/markdown/","title":"Markdown","text":"Markdown Implementation"},{"location":"docs/0/0/markdown/#toc","title":"Table of Contents","text":"
  • Base Implementation
  • Extended Syntax
    • Math Expression
"},{"location":"docs/0/0/markdown/#base-implementation","title":"Base Implementation","text":"

md2pdf uses Python-Markdown/markdown to convert Markdown to HTML which, apparently, is a Python implementation of John Gruber's markdown

According to the cited program's documentation, the specification is implemented as close to the reference specification as possible. In this link, you will see difference of the Python implementation and the original implementation.

And oh yes, this is an arguably messy implementation of Markdown, as opposed to Commonmark Markdown. But we got to make do of what we have, no? baka baka :3

"},{"location":"docs/0/0/markdown/#extended-syntax","title":"Extended Syntax","text":"

md2pdf extended the base implementation, and hereinunder are the details.

"},{"location":"docs/0/0/markdown/#extended-syntax-math-expression","title":"Math Expression","text":"

KaTeX expressions are supported in this program. You just need to surround it in a code block, with the language set as math. An example of this is the following:

```math\n% \\f is defined as #1f(#2) using the macro\n\\f\\relax{x} = \\int_{-\\infty}^\\infty\n    \\f\\hat\\xi\\,e^{2 \\pi i \\xi x}\n    \\,d\\xi\n```\n

This link lists all of the supported functions in KaTeX, grouped logically.

"},{"location":"docs/0/0/api/","title":"src","text":""},{"location":"docs/0/0/api/#sub-modules","title":"Sub-modules","text":"
  • src.cli
  • src.globals
  • src.info
  • src.md_pp
  • src.pdfgenerator
  • src.utils
"},{"location":"docs/0/0/api/cli/","title":"src.cli","text":"Functions hmc
(raw_HTML:\u00a0str, HTML_path:\u00a0str, raw_MD:\u00a0str, MD_path:\u00a0str, hf:\u00a0bool\u00a0|\u00a0None\u00a0=\u00a0None) \u2011> str\n

HTML or Markdown chooser.

Return first argument that is not None and convert it into HTML, if it is not already.

Args:
  • raw_HTML (str): Raw HTML string.
  • HTML_path (str): Path to HTML file.
  • raw_MD (str): Raw Markdown string.
  • MD_path (str): Path to Markdown file.
Returns:

string: Raw HTML string.

mc
(raw_MD:\u00a0str, MD_path:\u00a0str, hf:\u00a0bool\u00a0|\u00a0None\u00a0=\u00a0None) \u2011> str\u00a0|\u00a0None\n

Markdown chooser.

Return first argument that is not None and convert it into HTML.

Args:
  • raw_MD (str): Raw Markdown string.
  • MD_path (str): Path to Markdown file.
Returns:

string: Raw HTML string.

"},{"location":"docs/0/0/api/globals/","title":"src.globals","text":""},{"location":"docs/0/0/api/info/","title":"src.info","text":"Variables

CHOLDER HTML text of copyright holders of this project

PROJECT_NAME Project's name

SVER The current version of the project, compliant with the semver.

This project uses a modified semver. For more information, visit this link.

VARIANT The application variant

This is useful for debugging, and for initializing the application's configuration. Following are the allowed variants:

  • installable: for when the application is packed as an installable application
  • package: for when the application is published on PyPi (as a Python Library)
  • portable: for when the application is packed as a portable application

VLS The current version of the project as a list.

The list consists of 6 integers, which represent the following: - User - Dev - Minor - Patch - Prerelease Identifier The prerelease identifier number corresponds to the following values: 0: alpha 1: beta 2: release candidate or rc 3: none - Prerelease Version

"},{"location":"docs/0/0/api/md_pp/","title":"src.md_pp","text":"Functions get_bin_cmd
() \u2011> list[str]\n
htmlsvg2img
(html:\u00a0str) \u2011> str\n
katex2html
(marker:\u00a0str, tex:\u00a0str) \u2011> tuple[str,\u00a0str]\n
make_marker_id
(text:\u00a0str) \u2011> str\n
mdblocks_katex2img
(mdblocks:\u00a0dict[str,\u00a0str]) \u2011> list[typing.Any]\n
Classes FencedBlockPostprocessor
(md:\u00a0str, ext:\u00a0src.md_pp.WhExtension)\n

Postprocessors are run after the ElementTree it converted back into text.

Each Postprocessor implements a \"run\" method that takes a pointer to a text string, modifies it as necessary and returns a text string.

Postprocessors must extend markdown.Postprocessor.

Ancestors (in MRO)
  • markdown.postprocessors.Postprocessor
  • markdown.util.Processor
Methods run
(self, text:\u00a0str) \u2011> str\n

Subclasses of Postprocessor should implement a run method, which takes the html document as a single text string and returns a (possibly modified) string.

FencedBlockPreprocessor
(md:\u00a0str, ext:\u00a0src.md_pp.WhExtension)\n

Preprocessors are run after the text is broken into lines.

Each preprocessor implements a \"run\" method that takes a pointer to a list of lines of the document, modifies it as necessary and returns either the same pointer or a pointer to a new list.

Preprocessors must extend markdown.Preprocessor.

Ancestors (in MRO)
  • markdown.preprocessors.Preprocessor
  • markdown.util.Processor
Methods run
(self, lines:\u00a0list[str]) \u2011> list[str]\n

Each subclass of Preprocessor should override the run method, which takes the document as a list of strings split by newlines and returns the (possibly modified) list of lines.

WhExtension
(**kwargs:\u00a0dict[str,\u00a0typing.Any])\n

Base class for extensions to subclass.

Initiate Extension and set up configs.

Ancestors (in MRO)
  • markdown.extensions.Extension
Methods extendMarkdown
(self, md:\u00a0markdown.core.Markdown) \u2011> None\n

Add the various processors and patterns to the Markdown Instance.

This method must be overridden by every extension.

Keyword arguments:

  • md: The Markdown instance.

  • md_globals: Global variables in the markdown module namespace.

reset
(self) \u2011> None\n
"},{"location":"docs/0/0/api/pdfgenerator/","title":"src.pdfgenerator","text":"Functions calc_margin
(margin:\u00a0list[float], header_height:\u00a0int, footer_height:\u00a0int) \u2011> str\n
get_element
(boxes, element)\n

Given a set of boxes representing the elements of a PDF page in a DOM-like way, find the box which is named element.

Notes: - When Weasyprint renders an html into a PDF, it goes though several intermediate steps. Here, in this class, we deal mostly with a box representation: 1 Document have 1 Page or more, each Page 1 Box or more. Each box can contain other box. Hence the recursive method get_element for example. For more, visit the following links: - https://weasyprint.readthedocs.io/en/stable/hacking.html#dive-into-the-source - https://weasyprint.readthedocs.io/en/stable/hacking.html#formatting-structure

margin_preprocessor
(margin:\u00a0list[str]) \u2011> list[float]\n
Classes PDFGenerator
(*, main_html:\u00a0str, stylesheets:\u00a0list[str], first_page_header_html=builtins.str, first_page_footer_html=builtins.str, header_html:\u00a0str, footer_html:\u00a0str, base_url:\u00a0str, size:\u00a0str, margin:\u00a0list[str])\n

Generate a PDF out of a rendered template, with the possibility to integrate nicely a header and a footer if provided.

Notes: - Warning: the logic of this class relies heavily on the internal Weasyprint API. This snippet was written at the time of the release 47, it might break in the future. - This generator draws its inspiration and, also a bit of its implementation, from this discussion in the library github issues: https://github.com/Kozea/WeasyPrint/issues/92 - Hello from whi_ne (https://github.com/whinee) in the past, modified slightly at the time of release 51. And yes, I struggled adding my own features.

Initialize PDF Generator.

Notes: - The size and margin arguments are applied to the PDF like CSS does. See https://developer.mozilla.org/en-US/docs/Web/CSS/@page/size and https://developer.mozilla.org/en-US/docs/Web/CSS/margin#syntax respectively for more details.

Args:
  • main_html (str): An HTML file (most of the time a template rendered into a string) which represents the core of the PDF to generate.
  • first_page_header_html (str): Optional HTML for the first page's header.
  • first_page_footer_html (str): Optional HTML for the first page's footer.
  • header_html (str): Optional HTML for header.
  • footer_html (str): Optional HTML for footer.
  • base_url (str): An absolute url to the page which serves as a reference to Weasyprint to fetch assets, required to get our media.
  • stylesheets (list[str]): Optional paths to stylesheets to be used for rendering the PDF.
  • size (str): CSS size property applied directly to each page.
  • margin (str): CSS margin property applied directly to each page.
Methods render_pdf
(self) \u2011> bytes\n

Return the rendered PDF.

Returns:

bytes: The rendered PDF.

"},{"location":"docs/0/0/api/utils/","title":"src.utils","text":""},{"location":"docs/0/0/api/utils/#super-module","title":"Super-module","text":"
  • src
"},{"location":"docs/0/0/api/utils/#sub-modules","title":"Sub-modules","text":"
  • src.utils.base_cli
  • src.utils.base_exc
  • src.utils.cd
  • src.utils.cfg
  • src.utils.exceptions
  • src.utils.style
  • src.utils.types
  • src.utils.utils
"},{"location":"docs/0/0/api/utils/base_cli/","title":"src.utils.base_cli","text":"Functions command
(group:\u00a0src.utils.base_cli.Group) \u2011> Callable[[Callable[...,\u00a0Any]],\u00a0Callable[...,\u00a0Any]]\n

Wrapper for click commands.

Args:
  • group (Group): Command group of the command to be under.
Returns:
  • Callable[[Callable[..., Any]], Callable[..., Any]]
command_group
(name:\u00a0Union[str,\u00a0Callable[...,\u00a0Any],\u00a0ForwardRef(None)]\u00a0=\u00a0None, **attrs:\u00a0Any) \u2011> src.utils.base_cli.Group\n
custom_command
(name:\u00a0Union[str,\u00a0Callable[...,\u00a0Any],\u00a0ForwardRef(None)]\u00a0=\u00a0None, cls:\u00a0Optional[Type[src.utils.base_cli.Command]]\u00a0=\u00a0None, **attrs:\u00a0Any) \u2011> Union[src.utils.base_cli.Command,\u00a0Callable[...,\u00a0src.utils.base_cli.Command]]\n
de_rcfg
() \u2011> src.utils.cd.CustomDict\n

Return parsed configuration file, fetched from the CFLOP.

Returns:

dict[Any, Any]: description

de_wcfg
(value:\u00a0dict[typing.Any,\u00a0typing.Any]\u00a0|\u00a0list[typing.Any]) \u2011> None\n

Write given value to the configuration file, fetched from the CFLOP.

Args:
  • value (dict[Any, Any] | list[Any]): dictionary to overwrite the configuration file, fetched from the CFLOP.
get_stg
(path:\u00a0str, **kwargs:\u00a0dict[str,\u00a0typing.Any]) \u2011> Optional[Any]\n
init
(idx:\u00a0int) \u2011> None\n
select
(message:\u00a0str, choices:\u00a0Union[Sequence[str\u00a0|\u00a0questionary.prompts.common.Choice\u00a0|\u00a0dict[str,\u00a0Any]],\u00a0dict[str,\u00a0Any]], default:\u00a0Optional[Any]\u00a0=\u00a0None, instruction:\u00a0str\u00a0|\u00a0None\u00a0=\u00a0None, qmark:\u00a0str\u00a0|\u00a0None\u00a0=\u00a0None, pointer:\u00a0str\u00a0|\u00a0None\u00a0=\u00a0None, style:\u00a0Optional[prompt_toolkit.styles.base.BaseStyle]\u00a0=\u00a0None, show_selected:\u00a0bool\u00a0|\u00a0None\u00a0=\u00a0None, ret_err:\u00a0bool\u00a0|\u00a0None\u00a0=\u00a0None, **kwargs:\u00a0dict[str,\u00a0typing.Any]) \u2011> tuple[bool,\u00a0typing.Any]\n
Classes Command
(name:\u00a0str\u00a0|\u00a0None, context_settings:\u00a0Optional[Dict[str,\u00a0Any]]\u00a0=\u00a0None, callback:\u00a0Optional[Callable[...,\u00a0Any]]\u00a0=\u00a0None, params:\u00a0Optional[List[ForwardRef('Parameter')]]\u00a0=\u00a0None, help:\u00a0str\u00a0|\u00a0None\u00a0=\u00a0None, epilog:\u00a0str\u00a0|\u00a0None\u00a0=\u00a0None, short_help:\u00a0str\u00a0|\u00a0None\u00a0=\u00a0None, options_metavar:\u00a0str\u00a0|\u00a0None\u00a0=\u00a0'[OPTIONS]', add_help_option:\u00a0bool\u00a0=\u00a0True, no_args_is_help:\u00a0bool\u00a0=\u00a0False, hidden:\u00a0bool\u00a0=\u00a0False, deprecated:\u00a0bool\u00a0=\u00a0False)\n

Commands are the basic building block of command line interfaces in Click. A basic command handles command line parsing and might dispatch more parsing to commands nested below it.

:param name: the name of the command to use unless a group overrides it. :param context_settings: an optional dictionary with defaults that are passed to the context object. :param callback: the callback to invoke. This is optional. :param params: the parameters to register with this command. This can be either :class:Option or :class:Argument objects. :param help: the help string to use for this command. :param epilog: like the help string but it's printed at the end of the help page after everything else. :param short_help: the short help to use for this command. This is shown on the command listing of the parent command. :param add_help_option: by default each command registers a --help option. This can be disabled by this parameter. :param no_args_is_help: this controls what happens if no arguments are provided. This option is disabled by default. If enabled this will add --help as argument if no arguments are passed :param hidden: hide this command from help outputs.

:param deprecated: issues a message indicating that the command is deprecated.

.. versionchanged:: 8.1 help, epilog, and short_help are stored unprocessed, all formatting is done when outputting help text, not at init, and is done even if not using the @command decorator.

.. versionchanged:: 8.0 Added a repr showing the command name.

.. versionchanged:: 7.1 Added the no_args_is_help parameter.

.. versionchanged:: 2.0 Added the context_settings parameter.

Ancestors (in MRO)
  • click.core.Command
  • click.core.BaseCommand
Methods get_help_option
(self, ctx:\u00a0click.core.Context) \u2011> Optional[click.core.Option]\n

Returns the help option object.

Group
(name:\u00a0str\u00a0|\u00a0None\u00a0=\u00a0None, commands:\u00a0Union[Dict[str,\u00a0click.core.Command],\u00a0Sequence[click.core.Command],\u00a0ForwardRef(None)]\u00a0=\u00a0None, **attrs:\u00a0Any)\n

A group allows a command to have subcommands attached. This is the most common way to implement nesting in Click.

:param name: The name of the group command. :param commands: A dict mapping names to :class:Command objects. Can also be a list of :class:Command, which will use :attr:Command.name to create the dict. :param attrs: Other command arguments described in :class:MultiCommand, :class:Command, and :class:BaseCommand.

.. versionchanged:: 8.0 The commmands argument can be a list of command objects.

Ancestors (in MRO)
  • click.core.Group
  • click.core.MultiCommand
  • click.core.Command
  • click.core.BaseCommand
Methods command
(self, *args:\u00a0Any, **kwargs:\u00a0Any) \u2011> Union[Callable[[Callable[...,\u00a0Any]],\u00a0src.utils.base_cli.Command],\u00a0src.utils.base_cli.Command]\n

A shortcut decorator for declaring and attaching a command to the group. This takes the same arguments as :func:command and immediately registers the created command with this group by calling :meth:add_command.

To customize the command class used, set the :attr:command_class attribute.

.. versionchanged:: 8.1 This decorator can be applied without parentheses.

.. versionchanged:: 8.0 Added the :attr:command_class attribute.

cao
(group:\u00a0src.utils.base_cli.Group)\n

Returns wrappers for a click command evaluated from the given arguments.

Args:
  • group (Group): Command group of the command to be under.
Methods arguments
(self) \u2011> Callable[[Callable[...,\u00a0Any]],\u00a0Callable[...,\u00a0Any]]\n

The arguments wrapper.

Returns:

Callable[[Callable[..., Any]], Callable[..., Any]]

command
(self) \u2011> Callable[[Callable[...,\u00a0Any]],\u00a0Callable[...,\u00a0Any]]\n

The command wrapper.

Returns:

Callable[[Callable[..., Any]], Callable[..., Any]]

kwargs_preprocessor
(self, func:\u00a0Callable[...,\u00a0Any]) \u2011> Callable[...,\u00a0Any]\n
option_the
(self, maxlen_type_string:\u00a0int, maxlen_opts_help:\u00a0int) \u2011> Callable[...,\u00a0tuple[str,\u00a0str,\u00a0str]]\n
options
(self) \u2011> Callable[[Callable[...,\u00a0Any]],\u00a0Callable[...,\u00a0Any]]\n

The options wrapper. My God in heaven, I'm agnostic, but please save me from all evil. Amen.

Returns:

Callable[[Callable[..., Any]], Callable[..., Any]]

wrap
(self, func:\u00a0Callable[...,\u00a0Any]) \u2011> Callable[...,\u00a0Any]\n
Args:
  • func (Callable[..., Any]): Function to be wrapped.
Returns:

Callable[..., Any]: Wrapped function.

"},{"location":"docs/0/0/api/utils/base_exc/","title":"src.utils.base_exc","text":"Functions c_exc
(cls:\u00a0Type[BaseException]) \u2011> Type[BaseException]\n

Decorator to raise a custom exception.

This function gives the class an init function that raises the exception. If the class does not inherit from any Exception, it will be automatically inherit from Exception. This function also wraps the Exception with c_exc_str method, for adding the __str__ method.

Args:
  • cls (BaseException | Object): The exception to modify.
Returns:

BaseException: The exception to raise.

c_exc_str
(cls:\u00a0Type[BaseException]) \u2011> Type[BaseException]\n

Decorator to add the str method to an exception.

Args:
  • cls (BaseException): The exception to add the str method to.
Returns:

BaseException: The exception to raise.

"},{"location":"docs/0/0/api/utils/cd/","title":"src.utils.cd","text":"Functions test
() \u2011> None\n
Classes BEHAVIOR
(value, names=None, *, module=None, qualname=None, type=None, start=1)\n

An enumeration.

Ancestors (in MRO)
  • enum.Enum
Class variables

append

insert

modify

CustomDict
(*args, **kwargs)\n

Custom dictionary.

Ancestors (in MRO)
  • builtins.dict
Methods dir
(self, path:\u00a0str\u00a0=\u00a0'c0VjUmVUX2NPZEUgYnkgd2hpX25l', de:\u00a0Any\u00a0=\u00a0'c0VjUmVUX2NPZEUgYnkgd2hpX25l', sep:\u00a0str\u00a0=\u00a0'/') \u2011> Any\n
traverse
(self, path:\u00a0str, elem:\u00a0Union[dict[str,\u00a0Any],\u00a0Sized], sep:\u00a0str, idx:\u00a0int\u00a0=\u00a00, og_path:\u00a0str\u00a0|\u00a0None\u00a0=\u00a0None) \u2011> Union[tuple[int,\u00a0Union[Any,\u00a0dict[str,\u00a0int]]],\u00a0Any]\n

summary

Return States | State || Return Type || Description | |--------:|-------------------------------------------:|:----------------------------------| | 0 || Any (Indexed Item) || Path fully traversed | | 1 || dict[str, int] (Kwargs for CDKeyError) || Path's not in element | | 2 || dict[str, int] (Kwargs for CDIndexError) || Path's current index not in range |

Callback States | State || Arguments Type || Description | |--------:|---------------------------------------------:|:-------------------------------------------| | 0 || dict (Indexed Item), str (key), int (idx) || Path fully traversed; Element type dict | | 1 || Sized (Indexed Item), int (key), int (idx) || Path fully traversed; Element type Sized |

Args:
path (str): _description_\nelem (dict[str, Any] | Sized): _description_\nsep (str): _description_\nidx (int, optional): _description_. Defaults to 0.\nog_path (Optional[str], optional): _description_. Defaults to None.\n
Raises:
CDKeyError: _description_\nCDKeyError: _description_\nCDKeyError: _description_\nCDIndexError: _description_\nCDTypeError: _description_\n
Returns:
Any: _description_\n
flowchart TD\n    start([start]) --> args[/path, value, elem/] --> a\n    a{elem isDict?}\n        a --> |yes| b{key in<br>elem}\n            b --> |yes| c{path fully<br>traversed?}\n                c -->\n|no| y[[\"traverse(<br>path=path[1:],<br>elem=elem[key]<br>)\"]]:::success\n                c --> |yes| x[/\"(0, elem[key])\"/]:::success\n            b --> |no| f([CDKeyError]):::error\n        a --> |no| g{elem isSized?}\n            g --> |no| l([\"CDTypeError;<br>exp dict/Sized\"]):::error\n                h --> |no| m([\"CDKeyError;<br>key empty\"]):::error\n                    i --> |no| n([\"CDKeyError;<br>key not int\"]):::error\n            g --> |yes| h{\"key notEmpty?\"}\n                h --> |yes| i{key int?}\n                    i --> |yes| j{key inRange?}\n                        j -->\n|no| w[/\"(1, {'idx': idx, 'ls_idx': ls_idx, 'len_iter': len_iter})\"/]:::success\n                        j ----> |yes| c\n\n    classDef success color:#83ce9e,stroke:#6fc890\n    classDef error color:#f3626b,stroke:#f14651
"},{"location":"docs/0/0/api/utils/cfg/","title":"src.utils.cfg","text":"Functions dcfg
(value:\u00a0dict[str,\u00a0typing.Any], ext:\u00a0str) \u2011> str\n

Dump the given value to a string with the given extension.

Args:
  • value (dict): Value to dump to a string.
  • ext (str): Extension to dump the value to.
Returns:

str: The dumped value.

pcfg
(d:\u00a0str, type:\u00a0str) \u2011> src.utils.cd.CustomDict\n

Parse the given string as the given type.

Args:
  • d (str): String to parse.
  • type (str): Type to parse the string as.
Returns:

CustomDict: The parsed string.

rcfg
(file:\u00a0str) \u2011> src.utils.cd.CustomDict\n

Read the contents of a file with the given file name.

Args:
  • file (str): File name of the file to read the contents of.
Returns:

CustomDict: The contents of the file.

wcfg
(file:\u00a0str, value:\u00a0dict[typing.Any,\u00a0typing.Any]\u00a0|\u00a0list[typing.Any]) \u2011> None\n

Write the given value to a file with the given file name.

Args:
  • file (str): File name of the file to write the value to.
  • value (dict[Any, Any] | list[Any]): Value to write to the file.
Classes ExtensionNotSupported
(*args:\u00a0list[typing.Any], **kwargs:\u00a0dict[str,\u00a0typing.Any])\n

Method or function hasn't been implemented yet.

Ancestors (in MRO)
  • builtins.NotImplementedError
  • builtins.RuntimeError
  • builtins.Exception
  • builtins.BaseException
"},{"location":"docs/0/0/api/utils/exceptions/","title":"src.utils.exceptions","text":"Classes CDExceptions
()\n
Class variables

API

Internals

CLIExceptions
()\n
Class variables

TerminalTooThin Common base class for all non-exit exceptions.

ValidationError

GeneralExceptions
()\n
Class variables

PrerequisiteNotFound

ValidationError

KatexExceptions
()\n
Class variables

NotFound Common base class for all non-exit exceptions.

"},{"location":"docs/0/0/api/utils/style/","title":"src.utils.style","text":"Variables

COLORS t1: F3F78D t2: FF8D5C t3: E84855 t4: B56B45 t5: 404E7C t6: 55828B t7: 4E8098

Functions pp
(t:\u00a0Any, ca:\u00a0bool\u00a0|\u00a0None\u00a0=\u00a0None, *args:\u00a0list[typing.Any], **kwargs:\u00a0dict[str,\u00a0typing.Any]) \u2011> None\n

Center rich printable objects, then pretty print it.

Args:
  • t (Any): Rich printable object to be centered, then pretty printed.
  • ca (bool, optional): Determines whether to center text in the group individually. Defaults to None.
split_text
(t:\u00a0str) \u2011> list[str]\n
text
(t:\u00a0str, *args:\u00a0list[typing.Any], ca:\u00a0bool\u00a0|\u00a0None\u00a0=\u00a0None, **kwargs:\u00a0dict[str,\u00a0typing.Any]) \u2011> rich.console.Group\n
Classes C
()\n
Class variables

h0

h1

h2

s0

s1

s2

S
()\n
Class variables

p0

p1

p_critical

p_error

p_warning

t0

t1

t2

t3

t4

t5

t6

t_critical

t_error

t_good

t_warning

ct
()\n
Static methods group
(*ls:\u00a0rich.console.ConsoleRenderable\u00a0|\u00a0rich.console.RichCast\u00a0|\u00a0str) \u2011> rich.console.Group\n

Group given list of rich printable objects.

Returns:

Group: Group of rich printable objects

table
(cols:\u00a0list[str], rows:\u00a0list[list[str]]) \u2011> None\n

Print table from given list of str and list of list of strings for the columns and rows respectively.

Args:
  • cols (list[str]): List of string for column labels.
  • rows (list[list[str]]): List of rows (list of strings).
"},{"location":"docs/0/0/api/utils/types/","title":"src.utils.types","text":""},{"location":"docs/0/0/api/utils/utils/","title":"src.utils.utils","text":"Functions dnrp
(file:\u00a0str, n:\u00a0Optional[int]\u00a0=\u00a0None) \u2011> str\n

Get the directory component of a pathname by n times recursively then return it.

Args:
  • file (str): File to get the directory of.
  • n (Optional[int], optional): Number of times to get up the directory???? Defaults to 1.
Returns:

str: The directory component got recursively by n times from the given pathname

dpop
(d:\u00a0dict[typing.Any,\u00a0typing.Any], pop:\u00a0list[int\u00a0|\u00a0list[str\u00a0|\u00a0int\u00a0|\u00a0tuple[str,\u00a0...]]\u00a0|\u00a0str], de:\u00a0Optional[Any]\u00a0=\u00a0None) \u2011> Any\n

Iterate through the preferred order of precedence (pop) and see if the value exists in the dictionary. If it does, return it. If not, return de.

Args:
  • d (Dict[Any, Any]): Dictionary to retrieve the value from.
  • pop (list[int | tuple[str | int | tuple] | str]): List of keys to iterate through.
  • de (Any, optional): Default object to be returned. Defaults to None.
Returns:

Any: Retrieved value.

dt
(dt:\u00a0str, format:\u00a0str) \u2011> str\n

Remove timezone from datetime and format it to ISO 8601 format.

Args:
  • dt (str): Unformatted datetime string to be formatted to ISO 8601 format
  • format (str): The initial format of the datetime string
Returns:

str: Formatted datetime string

dt_ts
(ts:\u00a0str) \u2011> str\n

Convert the given unix timestamp to ISO 8601 format.

Args:
  • ts (str): unix timestamp to be converted to ISO 8601 format
Returns:

str: Formatted datetime string

file_exists
(fp:\u00a0str) \u2011> str\n

Check if the given file path exists.

Args:
  • fp (str): File path to check if it exists.
Raises:
  • exceptions.GeneralExceptions.ValidationError.FileNotFound: Raised when a file in the path is not found.
Returns:

str: Return fp when file path exists.

fill_ls
(*, ls:\u00a0Sequence[Any], length:\u00a0int, filler:\u00a0Optional[Any]\u00a0=\u00a0None) \u2011> Sequence[Any]\n

Fill given list (ls) with filler up to length.

Args:
  • ls (types.SequenceAny): List to fill with filler up to length
  • length (int): Length of the list to achieve.
  • filler (Optional[Any], optional): Filler to use. Defaults to None.
Returns:

types.SequenceAny: Filled list.

inmd
(p:\u00a0str, ls:\u00a0Optional[list[str]]\u00a0=\u00a0None) \u2011> str\n

\"If Not os.path.isdir, Make Directories\"

Args:
  • p (str): The path to be created, if it does not exist.
  • ls(Optional[list[str]], optional): List to append directories to that are not found and successfully created. Defaults to None.
Returns:

str: The path given.

iter_ls_with_items
(ls:\u00a0list[typing.Any], *items:\u00a0list[typing.Any]) \u2011> Generator[tuple[Any,\u00a0...],\u00a0None,\u00a0None]\n
ivnd
(var:\u00a0Any, de:\u00a0Any) \u2011> Any\n

If Var is None, return Default else var.

Args:
  • var (Any): Variable to check if it is None.
  • de (Any): Default value to return if var is None.
Returns:

Any: var if var is not None else de.

le
(expr:\u00a0str) \u2011> Any\n

Literal Evaluation

Args:
  • expr (str): Expression to be evaluated.
Returns:

Any: Expression literally evaluated.

noop
(*args:\u00a0list[typing.Any], **kwargs:\u00a0dict[str,\u00a0typing.Any]) \u2011> None\n

No operation

noop_single_kwargs
(arg:\u00a0Any) \u2011> Any\n
repl
(s:\u00a0str, repl_dict:\u00a0dict[str,\u00a0list[str]]) \u2011> str\n

Iterate through the dictionary, find the values in the given string and replace it with the corresponding key, and output the modified string.

Args:
  • s (str): String to modify.
  • repl_dict (dict[str, list[str]]): key-value pairs to replace string within the given string.
Returns:

str: Modified string.

rfnn
(*args:\u00a0list[typing.Any]) \u2011> Any\n

Return First Non-None

Return the first argument that is not None, else return None.

Returns:

Any: The first argument that is not None, else None.

run_mp
(func:\u00a0Callable[...,\u00a0Any], iterable:\u00a0Iterable[Any]) \u2011> list[typing.Any]\n
run_mp_qgr
(func:\u00a0Callable[...,\u00a0Any], iterable:\u00a0Iterable[Any]) \u2011> tuple[None]\u00a0|\u00a0tuple[typing.Any]\u00a0|\u00a0tuple[typing.Any,\u00a0...]\n
run_mp_qir
(func:\u00a0Callable[...,\u00a0Any], iterable:\u00a0Iterable[Any], callback:\u00a0Callable[...,\u00a0Any]) \u2011> None\n

Run multiprocessing.Pool().map_async(), and quit in return.

Iterate over iterable and apply iterated item to func asynchronously. Wait for a single process in the pool to return, and terminate the pool.

This function requires the given function to return a bool, or an iterable with its first item as a bool. This bool is then used to decide whether to trigger the callback and terminate the pool.

run_mp_star
(func:\u00a0Callable[...,\u00a0Any], iterable:\u00a0Iterable[Iterable[Any]]) \u2011> list[typing.Any]\n
run_mp_star_qgr
(func:\u00a0Callable[...,\u00a0Any], iterable:\u00a0Iterable[Iterable[Any]]) \u2011> tuple[None]\u00a0|\u00a0tuple[typing.Any]\u00a0|\u00a0tuple[typing.Any,\u00a0...]\n
run_mp_star_qir
(func:\u00a0Callable[...,\u00a0Any], iterable:\u00a0Iterable[Iterable[Any]], callback:\u00a0Callable[...,\u00a0Any]) \u2011> None\n

Run multiprocessing.Pool().starmap_async(), and quit in return.

Iterate over iterable and apply iterated items to func asynchronously. Wait for a single process in the pool to return, and terminate the pool.

sanitize_text
(s:\u00a0str) \u2011> str\n

Sanitize input text.

Reference: https://stackoverflow.com/a/93029

Args:
  • s (str): Text to be sanitized.
Returns:

str: Sanitized text.

squery
(query:\u00a0str, possibilities:\u00a0list[str], cutoff:\u00a0int\u00a0|\u00a0float\u00a0=\u00a00.6, *, processor:\u00a0Callable[[Any],\u00a0Any]\u00a0=\u00a0<function <lambda>>) \u2011> Generator[tuple[None,\u00a0str]\u00a0|\u00a0tuple[float,\u00a0str],\u00a0None,\u00a0None]\n

Custom search query.

Args:
  • query (str): String to search for in the possibilities.
  • possibilities (list[str]): The possibilities to search from.
  • cutoff (int | float, optional): The minimum percentage of similarity from the given possibilities. Defaults to 0.6.
  • processor (Callable[[Any], Any], optional): Processes the possibilities before comparing it with the query. Defaults to lambda x: x.
Returns:

Generator[tuple[None, str] | tuple[float, str], None, None]: Generator object of mastching search quries.

str2int
(s:\u00a0str) \u2011> Optional[int]\n

If given string is decimal, convert string to integer, else return False.

Args:
s (str): string to convert to integer.\n
Returns:
bool: _description_\n
which_ls
(cmd:\u00a0str, mode:\u00a0Optional[int]\u00a0=\u00a0None, path:\u00a0str\u00a0|\u00a0None\u00a0=\u00a0None) \u2011> Union[tuple[str],\u00a0tuple[str,\u00a0...],\u00a0ForwardRef(None)]\n

Yoinked from shutil. Given a command, mode, and a PATH string, return the path which conforms to the given mode on the PATH, or None if there is no such file.

mode defaults to os.F_OK | os.X_OK. path defaults to the result of os.environ.get(\"PATH\"), or can be overridden with a custom search path.

Classes CallbackGetResult
()\n
Methods callback
(self, *args:\u00a0list[typing.Any]) \u2011> None\n
get
(self) \u2011> tuple[None]\u00a0|\u00a0tuple[typing.Any,\u00a0...]\n
ExtInquirerControl
(choices:\u00a0Sequence[Union[str,\u00a0questionary.prompts.common.Choice,\u00a0Dict[str,\u00a0Any]]], default:\u00a0Union[str,\u00a0questionary.prompts.common.Choice,\u00a0Dict[str,\u00a0Any],\u00a0ForwardRef(None)]\u00a0=\u00a0None, pointer:\u00a0str\u00a0|\u00a0None\u00a0=\u00a0'\u00bb', use_indicator:\u00a0bool\u00a0=\u00a0True, use_shortcuts:\u00a0bool\u00a0=\u00a0False, show_selected:\u00a0bool\u00a0=\u00a0False, use_arrow_keys:\u00a0bool\u00a0=\u00a0True, initial_choice:\u00a0Union[str,\u00a0questionary.prompts.common.Choice,\u00a0Dict[str,\u00a0Any],\u00a0ForwardRef(None)]\u00a0=\u00a0None, **kwargs:\u00a0Any)\n

Control that displays formatted text. This can be either plain text, an :class:~prompt_toolkit.formatted_text.HTML object an :class:~prompt_toolkit.formatted_text.ANSI object, a list of (style_str, text) tuples or a callable that takes no argument and returns one of those, depending on how you prefer to do the formatting. See prompt_toolkit.layout.formatted_text for more information.

(It's mostly optimized for rather small widgets, like toolbars, menus, etc...)

When this UI control has the focus, the cursor will be shown in the upper left corner of this control by default. There are two ways for specifying the cursor position:

  • Pass a get_cursor_position function which returns a Point instance with the current cursor position.

  • If the (formatted) text is passed as a list of (style, text) tuples and there is one that looks like ('[SetCursorPosition]', ''), then this will specify the cursor position.

Mouse support:

The list of fragments can also contain tuples of three items, looking like:\n(style_str, text, handler). When mouse support is enabled and the user\nclicks on this fragment, then the given handler is called. That handler\nshould accept two inputs: (Application, MouseEvent) and it should\neither handle the event or return `NotImplemented` in case we want the\ncontaining Window to handle this event.\n

:param focusable: bool or :class:.Filter: Tell whether this control is focusable.

:param text: Text or formatted text to be displayed. :param style: Style string applied to the content. (If you want to style the whole :class:~prompt_toolkit.layout.Window, pass the style to the :class:~prompt_toolkit.layout.Window instead.) :param key_bindings: a :class:.KeyBindings object. :param get_cursor_position: A callable that returns the cursor position as a Point instance.

Ancestors (in MRO)
  • questionary.prompts.common.InquirerControl
  • prompt_toolkit.layout.controls.FormattedTextControl
  • prompt_toolkit.layout.controls.UIControl
Class variables

answer_text

ExtQuestion
(application:\u00a0Application[Any])\n

A question to be prompted.

This is an internal class. Questions should be created using the predefined questions (e.g. text or password).

Ancestors (in MRO)
  • questionary.question.Question
Class variables

kbi

Methods ask
(self, patch_stdout:\u00a0bool\u00a0|\u00a0None\u00a0=\u00a0None, **kwargs:\u00a0dict[str,\u00a0typing.Any]) \u2011> tuple[bool,\u00a0typing.Any]\n

Ask the question synchronously and return user response.

Args:
  • patch_stdout (bool, optional): Ensure that the prompt renders correctly if other threads are printing to stdout. Defaults to None.
Returns:

Any: The answer from the question.

PoolTerminate
(pool:\u00a0multiprocessing.pool.Pool, callback:\u00a0Callable[...,\u00a0Any])\n
Methods inner
(self, err:\u00a0bool, *args:\u00a0list[typing.Any], **kwargs:\u00a0dict[str,\u00a0typing.Any]) \u2011> None\n
"},{"location":"docs/0/0/contribute/","title":"Index","text":"For Contributors
  • Translating md2pdf
"},{"location":"docs/0/0/contribute/translations/","title":"Translations","text":"Translations"},{"location":"docs/0/0/contribute/translations/#toc","title":"Table of Contents","text":"
  • Summary
  • Definition of Terms
  • Translation Directory
  • Notes for Translators
    • Rule of Thumb
    • Variables
  • Translation File
    • Structure
      • metadata
        • version
          • For The Author
          • For The Translators
        • contributors
          • name
          • desc
          • links
            • anilist
            • discord
            • email
            • github
            • reddit
            • twitter
      • splash
        • str
        • desc
        • tln
      • text
        • {scope}
          • {class}
            • {key}
              • str
              • desc
              • tln
"},{"location":"docs/0/0/contribute/translations/#summary","title":"Summary","text":"

While there are no future plans for expanding to the global audience, of which most does not speak English, this application is ready for internationalization.

"},{"location":"docs/0/0/contribute/translations/#definition-of-terms","title":"Definition of Terms","text":"

i18n (abbreviation, numeronym): stands for internationalization; process of designing a software application so that it can be adapted to various languages and regions without engineering changes

"},{"location":"docs/0/0/contribute/translations/#translation-directory","title":"Translation Directory","text":"

The files that contain the translations can be located at ./dev/constants/version/{u}/{d}/lang/

whereas:

  • {u} refers to the user version that uses the constants under this directory
  • {d} refers to the dev version that uses the constants under this directory
Notes: For more information, visit the notes for whi~nyaan!."},{"location":"docs/0/0/contribute/translations/#notes-for-translators","title":"Notes for Translators","text":"

For those who want to translate this application, please read all of the following text.

"},{"location":"docs/0/0/contribute/translations/#notes-for-translators-rule-of-thumb","title":"Rule of Thumb","text":"

This is written by the author with no consideration for other languages. And as such, recommendations and suggestions are highly appreciated.

  • Any technical terminologies should be left untranslated, unless noted by the author (developer) otherwise.
  • Any technical phrase that cannot be translated properly to the target language should be translated without oversimplifying; Oversimplification might lead to a misunderstanding
  • Unless the tone affects the meaning of the text or unless stated otherwise, translators should not preserve the author's tone and should translate it with a neutral tone
"},{"location":"docs/0/0/contribute/translations/#notes-for-translators-variables","title":"Variables","text":"

You might see a text that is enclosed in a bracket, like the following:

{version}\n

These are variables, and are replaced with information in the application before displaying them to the user.

So, our example would be displayed to the users as such:

69.4.20\n

As you can see, it is crucial for displaying information to the users.

When translating a piece of text, make sure to put these variables in an appropriate place, and do not translate its name.

As an example, we will translate this English text:

Thank you for using {app_name}!\n

To Tagalog:

Sa paggamit ng {app_name}, ako ay taos-pusong nagpapasalamat sa iyong pagtangkilik!\n

The variable's name is not translated.

In this next example, the variable is already in a fixed position:

{app_name} version: {version}\n

The Tagalog translation should look like this:

bersyon ng {app_name}: {version}\n

The app_name variable changed places to translate properly. However, there is no need for version to do so, as it is formatted.

"},{"location":"docs/0/0/contribute/translations/#translation-file","title":"Translation File","text":"

A translation file can be found under the translation directory.

Whereas, its name is ISO 639-1 language code that corresponds to its contained translations.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure","title":"Structure","text":""},{"location":"docs/0/0/contribute/translations/#translation-file-structure-metadata","title":"metadata","text":"

Metadata of the translation.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-metadata-version","title":"version","text":"

Version of the translation.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-metadata-version-for-the-author","title":"For The Author","text":"

Given a version number major.minor.patch, bump the:

  • major version when you make a significant change in the contents of a text or the description along side it, that you think it warrants a change in all of the translations.

  • minor version when you make a change in the contents of a text or the description along side it, which does not warrant a change in all of the translations. Example are modifying text to use much more understandable words.

  • patch version when you fix a typographical error in a text. This might induce a change in other translation, but does not warrant otherwise.

Changing the schema, or any key names shall warrant a dev version bump for the application. You break the english text for this application, you fix every other translation.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-metadata-version-for-the-translators","title":"For The Translators","text":"

As the app is written in English, follow the latest version of the english text.

The translation will be bumped as per the specification written here.

If you updated your translations to match that of the current English translation, change the version to the current version of the English translation.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-metadata-contributors","title":"contributors","text":"

List of translation contributors' information, for attribution purposes.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-metadata-contributors-name","title":"name","text":"

Name of the contributor.

It can be an alias, nickname, or a full name. As long as you are happy with being credited using that name, I have no problem with it.

Obscene and/or offensive names however will be apprehended. Otherwise, be creative.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-metadata-contributors-desc","title":"desc","text":"

Describe yourself.

If you're getting credited, go all out. You can even advertise your personal project. As long as the contents are not obscene or offensive, I'm fine with it.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-metadata-contributors-links","title":"links","text":"

Dictionary of links to your contacts, social media, and whatnot.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-metadata-contributors-links-anilist","title":"anilist","text":"

Anilist username.

Example:

anilist: whinyaan\n

Links to https://anilist.co/user/whinyaan.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-metadata-contributors-links-discord","title":"discord","text":"

Key-value pairs of Discord tag and their snowflake.

Example:

discord:\nwhi_ne#4783:\n848092597822160907\n

Links to whi_ne#4783.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-metadata-contributors-links-email","title":"email","text":"

List of electronic mail addresses.

Example:

email:\n- whinyaan@protonmail.com\n

Links to whinyaan@protonmail.com.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-metadata-contributors-links-github","title":"github","text":"

Github username.

Example:

github: whinee\n

Links to https://github.com/whinee.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-metadata-contributors-links-reddit","title":"reddit","text":"

Reddit username.

Example:

reddit: whi-nyaan\n

Links to https://reddit.com/user/whi-nyaan.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-metadata-contributors-links-twitter","title":"twitter","text":"

Twitter username.

Example:

twitter: whi_nyaan\n

Links to https://twitter.com/whi_nyaan.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-splash","title":"splash","text":"

Dictionary of random stuff to be displayed at startup of the application.

Example:

music_artist_rec:\n    str: Listen to Kanro! https://kanromusic.com\n    desc: Author's music artist recommendation\n
"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-splash-str","title":"str","text":"

The actual splash message.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-splash-desc","title":"desc","text":"

Description of the splash message. Might be useful to keep the translation accurate at an acceptable margin. Will not be displayed.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-splash-tln","title":"tln","text":"

Stands for translators' notes, used by translators to describe to the next translators any compromises done to translate the text to a certain language, or whatnot.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-text","title":"text","text":"

Dictionary of scopes, classes, and keys (dictionary) of text to display in the application.

Example:

cli:\n    init:\n        choose_language:\n            str: Choose language\n            desc: |-\n                Choose app language\n
"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-text-scope","title":"{scope}","text":"

There are three scopes allowed, but only the first two are applicable:

  • common
  • cli
  • gui

The first scope is class of keys that can be used in both the CLI and GUI versions of the app. This includes the description and motto of the program, prompts like yes or no, and whatnot. The rest is self-explanatory.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-text-scope-class","title":"{class}","text":"

This is where keys are categorized. For example, keys that convey information regarding the application can be put under the info class, while the keys that are used for prompting the users can be put under the prompt class.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-text-scope-class-key","title":"{key}","text":"

This is the name of the key. There is no general naming convention, but the developer seems to have one in her mind.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-text-scope-class-key-str","title":"str","text":"

The string in the language defined by the language file.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-text-scope-class-key-desc","title":"desc","text":"

Description of the key. Might be useful to keep the translation accurate at an acceptable margin. Will not be displayed.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-text-scope-class-key-tln","title":"tln","text":"

Stands for translators' notes, used by translators to describe to the next translators any compromises done to translate the text to a certain language, or whatnot.

"}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Home","text":"md2pdf Markdown to PDF converter For writing faster? No. For writing with *class*? Yusss

Github: github.com/whinee/md2pdf

Website: m2p.whinyaan.xyz

To be updated, be sure to watch this repository and join the Discord Support Server for this and other projects.

Interested in commissioning projects? Inquire through Discord(whi_ne#4783) or through e-mail(whinyaan@protonmail.com). Price starts at 30 USD.

"},{"location":"#toc","title":"Table of Contents","text":"
  • Important
  • Downloads
  • What\u2019s this?
    • Supported OSes
  • Usage
  • Getting Started
  • Advantages
  • Disadvantages
  • Translations
  • Known Issues and Limitations
  • Considerations
  • Contributions
  • License
    • MIT
  • Attribution
    • MIT Logo
    • Icons
  • Further Reading
"},{"location":"#important","title":"Important","text":"

md2pdf is still in Unreleased Alpha Development Stage.

Using the program at this stage is not recommended.

"},{"location":"#downloads","title":"Downloads","text":"

Since people are looking for the download first, here you go:

Follow this link to install md2pdf in your machine.

"},{"location":"#what-s-this","title":"What\u2019s this?","text":"

md2pdf is a Markdown to PDF converter that can also do a lot of stuff:

  • Headers and Footers
    • Can be in Markdown or HTML format
    • Support for first page header and footer
  • Print output HTML
  • Programmatic Usage
"},{"location":"#what-s-this-supported-oses","title":"Supported OSes","text":"
  • Windows
  • MacOS
  • Linux
"},{"location":"#usage","title":"Usage","text":"

This section is not yet complete.

"},{"location":"#getting-started","title":"Getting Started","text":"

The instructions will get you a copy of the project up and running on your local machine for development and testing purposes., visit this link

"},{"location":"#advantages","title":"Advantages","text":"
  • Standardized Styles
  • Consistent Results
  • Programmatic Usage
"},{"location":"#disadvantages","title":"Disadvantages","text":"
  • This program does not guarantee that you will be able to write faster, just be able to write in markdown (effectively plaintext) and produce consistent results (assuming that you use the same text, settings, stylesheet/s, and whatnot)
  • Have to link pictures online in order to attach one in the document, unlike in fancy word editors like Microsoft Word or LibreOffice Writer
"},{"location":"#translations","title":"Translations","text":"

This program is translation (i18n) ready!

Please refer to this link to learn more on how to create a translation for this program.

"},{"location":"#known-issues-and-limitations","title":"Known Issues and Limitations","text":"
  • This program can not be run in termux due to an inherent bug in AOSP that the said org's developers refuses to fix even if it will only take (apparently) a change in a single line of code (I forgot where the relevant Stackoverflow link is stored at, nor do I know the keywords for searching it up)
"},{"location":"#considerations","title":"Considerations","text":"

I want to implement more features as to extend the markdown specification, and in this link, you can see the following considerations to be made for future feature implementations.

If you want to help, check the TODO of the developer and the contribution guidelines.

"},{"location":"#contributions","title":"Contributions","text":"

For the contribution guidelines, visit this link.

For contributing in the latest version of md2pdf, visit this link

"},{"location":"#license","title":"License","text":""},{"location":"#mit","title":"MIT","text":"

Copyright for portions of project md2pdf are held by [Julien Maupetit, Github account jmaupetit owner, 2016-2021] as part of project md2pdf, by [c4ffein, Github account c4ffein owner, 2021-2022] as part of project txt2pdf, by [Simon Sapin, Github account SimonSapin owner, 2011-2023] as part of project WeasyPrint, by [Pallets, Github account pallets owner, 2014-2022] as part of project click, by [mbarkhau, Github account mbarkhau owner, 2019-2021] as part of project markdown-katex, by [Python-Markdown, Github account Python-Markdown owner, 2007-2023] as part of project markdown, by [whi_ne, Github account whinee owner, 2021-2022] as part of project MangDL, and by [whi_ne, Github account whinee owner, 2022] as part of project YAMHL.

All other copyright for project md2pdf are held by [Github Account whinee Owner, 2023].

Check the LICENSE for more details.

"},{"location":"#attribution","title":"Attribution","text":""},{"location":"#attribution-mit-logo","title":"MIT Logo","text":"

Massachusetts Institute of Technology (vectorized by Mysid, modified by whinee), Public domain, via Wikimedia Commons

"},{"location":"#attribution-icons","title":"Icons","text":"

Exclamation Mark, Code Fork, Star, Group, Code, and Discord icons by Icons8

NOTE: If a reference or source material is not attributed properly or not at all, please kindly message me at Discord: whi_ne#4783 or create a pull request so I can properly give credit to their respective authors.

"},{"location":"#further-reading","title":"Further Reading","text":"
  • Frequently Asked Questions
  • License Agreement
  • Latest Documentation (0.0.x.x)
  • All Documentation
  • Changelog
  • Latest Bump
  • Latest Commit
  • Notes for whi~nyaan!
  • whi~nyaan!'s diary
"},{"location":"changelog/","title":"Changelog","text":"Changelog"},{"location":"changelog/#0-0-0-0-0-0","title":"0.0.0.0-alpha.0","text":""},{"location":"considerations/","title":"Considerations","text":"Considerations for Future Feature Implementation"},{"location":"considerations/#toc","title":"Table of Contents","text":"
  • Page Breaks
  • Columns
  • GUI
"},{"location":"considerations/#page-breaks","title":"Page Breaks","text":"

There is no plain markdown way to add pagebreak in a markdown file. However, I came across this stackoverflow answer that mentions that the answer-er uses <<<<>>>> to denote pagebreak in their documents. And I liked that! And as such, I think I will implement just that in later versions of this program.

"},{"location":"considerations/#columns","title":"Columns","text":"

Before this project can even convert markdown to PDF files in sub-ten seconds, I have been using tables as substitute for columns. This is as the Commonmark Markdown specification does not support such feature.

However, there is a simple problem with tables in markdown: it does not support multi-line cells

Time and time again, I have searched for ways to be able to write multi-line cells in a kind of markdown way. All of them are ugly implementations. None of them can satisfy me.

And then I came across MultiMarkdown's table documentation which makes an interesting observation:

If you need complex tables you will need to create them by hand or with a tool specifically designed for your output format. At some point, however, you should consider whether a table is really the best approach if you find MultiMarkdown tables too limiting.

And I think that that is true.

However, I have thought of a solution. That is to parse markdown inside HTML tags. Such as that the following markdown...

<table>\n    <tr>\n        <th>Header</th>\n    </tr>\n    <tr>\n        <td>\n            - Lorem ipsum dolor sit amet\n            - Consectetur adipiscing elit\n            - Integer molestie lorem at massa\n        </td>\n    </tr>\n</table>\n

...will be converted to HTML like the following:

<table>\n    <tr>\n        <th>Header</th>\n    </tr>\n    <tr>\n        <td>\n            <ul>\n                <li>Lorem ipsum dolor sit amet</li>\n                <li>Consectetur adipiscing elit</li>\n                <li>Integer molestie lorem at massa</li>\n            </ul>\n        </td>\n    </tr>\n</table>\n

But, I think that the best solution would be to just make my own implementation of columns.

A solution I am considering at the time of writing is using a custom HTML tag called cols (stands for columns) that wraps col (stands for column) tags, which in turn wraps content in a column. Such as that the following markdown leads to 3 columns.

<cols>\n    <col>\n        Column #1\n    </col>\n    <col>\n        Column #2\n    </col>\n    <col>\n        Column #3\n    </col>\n</cols>\n

And yes, the content inside each col tags will be interpreted as markdown.

"},{"location":"considerations/#gui","title":"GUI","text":"

I do not have proper plans for the GUI of this project yet. But boredom does wonders.

I was once subjected to the horrors of national achievement test and mock exams for 4 days. And we are not allowed to use our phones for 4-5 hours straight a day, for 4 days. And so, I scribbled to a scratch paper that I had. And what do you know, I have this graph.

A week later, I graphed the thing in mermaid.js, and here it is:

sequenceDiagram\n    participant A as core.py\n    participant B as main.js\n    participant C as renderer.js\n\n    Note over A,C: Initialize\n\n    B -) C: Run\n    note left of C: show loading screen\n    B -) A: Run\n    alt log path is `None`\n        A ->> B: request Electron.js App Directory\n        note left of B: get Electron.js App Directory\n        B --) A: Electron.js App Directory\n    end\n\n    A ->> B: log path\n    C ->> B: ready\n    B ->> C: tx log path\n    note left of C: console.log(log path)\n    C ->> B: ack\n    B ->> A: tx ack\n    A ->> B: cfg\n    note left of B: process cfg\n    B ->> C: tx cfg\n    note left of C: remove loading screen\n\n    Note over A,C: Nominal Operation\n\n    alt log\n        B -) A: log\n        note right of A: log\n    end\n\n    alt log\n        C -)+ B: log\n        B -)- A: tx log\n        note right of A: log\n    end\n\n    alt mod cfg\n        B -) A: mod cfg\n        note right of A: rewrite cfg\n    end\n\n    alt mod cfg\n        C -)+ B: mod cfg\n        B -)- A: tx mod cfg\n        note right of A: rewrite cfg\n    end\n\n    alt ctl\n        B -) A: ctl\n        note right of A: process\n        alt res\n            A --) B: res\n            alt tx res\n                B --) C: tx res\n            end\n        end\n    end\n\n    alt ctl\n        C -) B: ctl\n        B -) A: tx ctl\n        note right of A: process\n        alt res\n            A --) B: res\n            alt tx res\n                B --) C: tx res\n            end\n        end\n    end
"},{"location":"contributing/","title":"Contributing","text":"Contributing to md2pdf

First off, thanks for taking the time to contribute! \u2764\ufe0f

All types of contributions are encouraged and valued. See the Table of Contents for different ways to help and details about how this project handles them. Please make sure to read the relevant section before making your contribution. It will make it a lot easier for us maintainers and smooth out the experience for all involved. The community looks forward to your contributions. \ud83c\udf89

And if you like the project, but just don't have time to contribute, that's fine. There are other easy ways to support the project and show your appreciation, which we would also be very happy about: - Star the project - Tweet about it - Refer this project in your project's README - Mention the project at local meetups and tell your friends/colleagues

"},{"location":"contributing/#toc","title":"Table of Contents","text":"
  • Code of Conduct
  • I Have a Question
  • I Want To Contribute
    • Legal Notice
    • Reporting Bugs
      • Before Submitting a Bug Report
      • How Do I Submit a Good Bug Report?
    • Suggesting Enhancements
      • Before Submitting an Enhancement
      • How Do I Submit a Good Enhancement Suggestion?
    • Your First Code Contribution
    • Improving The Documentation
  • Submitting a Pull Request
    • Dont\u2019s
  • Style guides
    • Commit Messages
    • Code
  • Join The Project Team
  • Attribution
"},{"location":"contributing/#code-of-conduct","title":"Code of Conduct","text":"

This project and everyone participating in it is governed by the md2pdf Code of Conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to <>.

"},{"location":"contributing/#i-have-a-question","title":"I Have a Question","text":"

If you want to ask a question, we assume that you have read the available Latest Documentation (0.0.x.x).

Before you ask a question, it is best to search for existing Issues that might help you. In case you have found a suitable issue and still need clarification, you can write your question in this issue. It is also advisable to search the internet for answers first.

If you then still feel the need to ask a question and need clarification, we recommend the following:

  • Open an Issue.
  • Provide as much context as you can about what you're running into.
  • Provide the following information:
    • OS name and version If in Linux, include linux distribution and kernel version; and
    • Python version

We will then take care of the issue as soon as possible.

"},{"location":"contributing/#i-want-to-contribute","title":"I Want To Contribute","text":""},{"location":"contributing/#i-want-to-contribute-legal-notice","title":"Legal Notice","text":"When contributing to this project, you must agree that you have authored 100% of the content, that you have the necessary rights to the content and that the content you contribute may be provided under the project license."},{"location":"contributing/#i-want-to-contribute-reporting-bugs","title":"Reporting Bugs","text":""},{"location":"contributing/#i-want-to-contribute-reporting-bugs-before-submitting-a-bug-report","title":"Before Submitting a Bug Report","text":"

A good bug report shouldn't leave others needing to chase you up for more information. Therefore, we ask you to investigate carefully, collect information and describe the issue in detail in your report. Please complete the following steps in advance to help us fix any potential bug as fast as possible.

  • Make sure that you are using the latest version.
  • Determine if your bug is really a bug and not an error on your side e.g. using incompatible environment components/versions (Make sure that you have read the Latest Documentation (0.0.x.x). If you are looking for support, you might want to check this section).
  • To see if other users have experienced (and potentially already solved) the same issue you are having, check if there is not already a bug report existing for your bug or error in the bug tracker.
  • Also make sure to search the internet (including Stack Overflow) to see if users outside of the GitHub community have discussed the issue.

  • Collect information about the bug

  • Stack trace (Traceback)
  • OS, Platform and Version (Windows, Linux, macOS, x86, ARM)
  • Version of the interpreter, compiler, SDK, runtime environment, package manager, depending on what seems relevant.
  • Possibly your input and the output
  • Can you reliably reproduce the issue? And can you also reproduce it with older versions?
"},{"location":"contributing/#i-want-to-contribute-reporting-bugs-how-do-i-submit-a-good-bug-report","title":"How Do I Submit a Good Bug Report?","text":"

You must never report security related issues, vulnerabilities or bugs including sensitive information to the issue tracker, or elsewhere in public. Instead sensitive bugs must be sent by email to <>.

We use GitHub issues to track bugs and errors. If you run into an issue with the project:

  • Open an Issue. (Since we can't be sure at this point whether it is a bug or not, we ask you not to talk about a bug yet and not to label the issue.)
  • Explain the behavior you would expect and the actual behavior.
  • Please provide as much context as possible and describe the reproduction steps that someone else can follow to recreate the issue on their own. This usually includes your code. For good bug reports you should isolate the problem and create a reduced test case.
  • Provide the information you collected in the previous section.

Once it's filed:

  • The project team will label the issue accordingly.
  • A team member will try to reproduce the issue with your provided steps. If there are no reproduction steps or no obvious way to reproduce the issue, the team will ask you for those steps and mark the issue as needs-repro. Bugs with the needs-repro tag will not be addressed until they are reproduced.
  • If the team is able to reproduce the issue, it will be marked needs-fix, as well as possibly other tags (such as critical), and the issue will be left to be implemented by someone.
"},{"location":"contributing/#i-want-to-contribute-suggesting-enhancements","title":"Suggesting Enhancements","text":"

This section guides you through submitting an enhancement suggestion for md2pdf, including completely new features and minor improvements to existing functionality. Following these guidelines will help maintainers and the community to understand your suggestion and find related suggestions.

"},{"location":"contributing/#i-want-to-contribute-suggesting-enhancements-before-submitting-an-enhancement","title":"Before Submitting an Enhancement","text":"
  • Make sure that you are using the latest version.
  • Read the Latest Documentation (0.0.x.x) carefully and find out if the functionality is already covered, maybe by an individual configuration.
  • Perform a search to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one.
  • Find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the project's developers of the merits of this feature. Keep in mind that we want features that will be useful to the majority of our users and not just a small subset. If you're just targeting a minority of users, consider writing an add-on/plugin library.
"},{"location":"contributing/#i-want-to-contribute-suggesting-enhancements-how-do-i-submit-a-good-enhancement-suggestion","title":"How Do I Submit a Good Enhancement Suggestion?","text":"

Enhancement suggestions are tracked as GitHub issues.

  • Use a clear and descriptive title for the issue to identify the suggestion.
  • Provide a step-by-step description of the suggested enhancement in as many details as possible.
  • Describe the current behavior and explain which behavior you expected to see instead and why. At this point you can also tell which alternatives do not work for you.
  • You may want to include screenshots and animated GIFs which help you demonstrate the steps or point out the part which the suggestion is related to. You can use this tool to record GIFs on macOS and Windows, and this tool or this tool on Linux.
  • Explain why this enhancement would be useful to most md2pdf users. You may also want to point out the other projects that solved it better and which could serve as inspiration.
"},{"location":"contributing/#i-want-to-contribute-your-first-code-contribution","title":"Your First Code Contribution","text":""},{"location":"contributing/#i-want-to-contribute-improving-the-documentation","title":"Improving The Documentation","text":""},{"location":"contributing/#submitting-a-pull-request","title":"Submitting a Pull Request","text":"

This is based on Michael Herrmann's gist titled Good PRs are minimal.

Every Pull Request (hereinafter referred to as PR) should have one, and only one, unique goal. The PR should make the absolute minimum number of changes that are required to achieve this goal.

The fewer things you change, the easier it will be for the team to see what you did, and thus gain confidence that you PR makes sense.

"},{"location":"contributing/#submitting-a-pull-request-dont-s","title":"Dont\u2019s","text":"
  • Changing whitespace unnecessarily, eg. switching tabs and spaces.

    This leads to huge numbers of unnecessarily changed lines of code.

  • Running a linter not listed in the linters currently used by the project

  • Don't unnecessarily introduce new tools or dependencies. I'm sure you have your favorites. But don't force them on me or other contributors. Stick to those that are absolutely required, or come with the language.
  • Obey the same code style as the library: Tabs or spaces, maximum line length, etc.

In short: Good PRs are minimal. You're very welcome to add several improvements. But please make them in separate PRs.

"},{"location":"contributing/#style-guides","title":"Style guides","text":""},{"location":"contributing/#style-guides-commit-messages","title":"Commit Messages","text":"

This repository does not enforce a style guide on commits. However, it is highly recommended to be concise and informative when writing commit messages.

"},{"location":"contributing/#style-guides-code","title":"Code","text":"

This project uses the following linters for the

"},{"location":"contributing/#join-the-project-team","title":"Join The Project Team","text":""},{"location":"contributing/#attribution","title":"Attribution","text":"

This guide is based on the contributing-gen. Make your own!

"},{"location":"diary/","title":"Diary","text":"r/offmychest

Written below are rants and lessons I have learned in making this project, and whatnot. Basically, I do not know, I just want to get it out of my chest.

"},{"location":"diary/#toc","title":"Table of Contents","text":"
  • KaTeX Support
"},{"location":"diary/#katex-support","title":"KaTeX Support","text":"

For this project, I planned it to ship with a KaTeX support.

I have only found a single python-markdown extension that is also compatible with Weasyprint, and that is markdown-katex by mbarkhau. However, it is so dang slow.

From my testing, it takes about 200 seconds (or roughly over 3 mins) to convert a markdown file with around 5-10 formulae in it to a 200 kb PDF file, which is about a kbps. However, that is a shitty metric, as there is an image in there, but you get the point, It is slow as fuck.

Now, what I did is attempt to rewrite mbarkhau's implementation of KaTeX for python-markdown. Built it from the ground up, taking motivation from the original project and some other extensions along the way. Heavily rebuilding the logic behind the things that I figured out takes up most of the time.

I narrowed it down to two things that slows it down the most: the preprocessor and postprocessor functions. I figured out that the iterator for feeding KaTeX formulae into the KaTeX binary took the longest as the process persists for quite a while on my machine's process monitoring tool. And as such, I made that process multithreaded.

Weeks after almost achieving feature-parity with the original project, I encountered an error. It was not of my program, but of the python-markdown's. And as such, I dug up the code that caused that error and extracted that to my program to be able to modify the code and remove the snippet that causes the error in the first place. And of course, that affected the rendering process.

There's no more hope. I did something wrong, and I can not track down where it went wrong.

Then, it finally hit me. The problem is when I attempted to rebuild the already perfect python-markdown KaTeX implementation. I just need to make it multithreaded. And while I still need to extract the stuff to make it work with the other stuff that I plan to add, I still only need to modify about 20% of the original project. I am so fucking dumb.

Or so I thought, two weeks later, after doing just that, it's still slow. And what I mean by slow is that I can run the program, wash the plate I used for eating the leftover cake for like about a minute or two, make myself a cup of coffee, and come back to that damn thing still running! Luckily, I narrowed it down to the very root cause of it all: the logic that searches for the KaTeX binary in the machine.

I do not know how or why the heck is it so slow. In any case, I replaced it with a shutil's implementation of which, modified to work with the extension. And fortunately, it worked! The logic still looks the same as the old one, but the damn thing runs from 30 secs down to sub-five seconds, depending where the binary is at. Like, whaaaaaat?!?!

What is the moral of the story then? That someone's code might actually be the best solution for the problem. But if it does not work, then do not try to rebuild it from the ground up. See first if you can modify some parts of it to work with your problem. Then if it does not work, then proceed to rebuilding it. As often times, that solution might be the best solution for that exact problem, but not for your own, exact problem.

Or is that it?

Maybe I just wanted to rant about the stupid weeks I have wasted for this little thing to fucking work? Or is it because I just wanted to flex how much I have optimized a single thing?

I do not fucking know, but I sure did flex'd to my friends about how I \"optimized\" a program to run 40x faster. I mean, where is the lie?

Now, where am I again? Oh, right, KaTeX support. Yay, finally added! UwU

"},{"location":"faq/","title":"Faq","text":"FAQ"},{"location":"faq/#toc","title":"Table of Contents","text":"
  • Is this application safe?
  • What are your intentions in making this application?
  • Who are you?
"},{"location":"faq/#is-this-application-safe","title":"Is this application safe?","text":"TL;DR: First of all, safe from what aspect, bruv? Considering that you are asking this, probably not. Is this application safe for my computer? TL;DR: Yes, but not really. Safe enough to put a 99.99% safety guarantee on it, air commercials of it, and not get sued on the grounds of false advertisement.

No software is ever safe, and there will never be. Unless if we, for some mysterious and divine reason, gain the ability to prove if a program halts or not, which in this universe is impossible (relevant link: Halting problem).

Enough of explaining the philosophical implications of this problematic question, and let us go to the real meat of the discussion. No, I can not assure you, as the developer of this application, that this application is safe. It is like asking if I poisoned your food; regardless of if I did it or not, I will dutifully deny the allegation, duh. Inquired you did, now trust me. Make of that what you will, but I am here to chase clout and make money out of it, not to compromise machines.

Well, with all that said, I also made it for personal use. And for that, I have to make it at the very least usable to the extent that it would not compromise the host machine that it is running on.

Don't trust me? The application is open-sourced. Every packaged application downloaded from the official site and Github repository is built from the same source as available on the official Github repository. If you know how to read the source code, you are free to do so, and inspect it. If you did do so, please hunt down some bugs for me. Much appreciated UwU

To end this answer, well... I mean, you could run the thing on a virus checker. Although, what might be an innocuous yet insecure system API call might be flagged as a suspicious activity. Not that I am aware of anything of that sort in my application, but I think that that will suffice as an example.

"},{"location":"faq/#what-are-your-intentions-in-making-this-application","title":"What are your intentions in making this application?","text":"TL;DR: It's a hobby of mine. It is not driven by money or ill intentions. Inquired you did, now trust me.

This started out as a hobby project. To pass time, and live out the rest of my days as a virgin NEET and a total social recluse. Assuming that you can see this site right now, it has grew into this large and popular project that it has become.

My intentions however are still the same as it was months ago. However, I have a side goal in mind right now: to attain popularity in the open source scene, enough to get me enough freelancing work and earn money.

Yes, that is it, really. I am in it for the money, but the development of this application is but money-driven. I mean, I would very much appreciate it if you could donate money or a little bit of your time to this little endeavour of mine, or commission me to do some work for you.

"},{"location":"faq/#who-are-you","title":"Who are you?","text":"TL;DR: That's a creepy thing to ask dude, I'm a teenager. \\s

Hello, I am whi_ne, short for whitespace_negative. 17 at the time of writing. I am a python and a web developer, albeit shitty at both of them. I also do some freelance work. Nice to meet ya!

Yes, I use an alias; personal branding is dead. I also want to stay anonymous. However, my pics on multiple guys' DMs suggests otherwise. And yes, please do not dig up dirt on me, I will let you know everything there is to know about me.

"},{"location":"latest-bump/","title":"Latest bump","text":"Latest Version Bump"},{"location":"latest-bump/#0000-alpha0","title":"0.0.0.0-alpha.0","text":"

<font color=\""},{"location":"latest-commit/","title":"Latest commit","text":"Latest Commit"},{"location":"latest-commit/#summary","title":"Summary","text":"

Yet 'nother fucking oopsies...

"},{"location":"latest-commit/#changes","title":"Changes","text":""},{"location":"latest-release-notes/","title":"Latest release notes","text":"0.0.0.0-alpha.0"},{"location":"latest-release-notes/#description","title":"Description","text":"

<font color=\""},{"location":"license/","title":"License","text":"MIT LICENSE

Copyright for portions of project md2pdf are held by [Julien Maupetit, Github account jmaupetit owner, 2016-2021] as part of project md2pdf, by [c4ffein, Github account c4ffein owner, 2021-2022] as part of project txt2pdf, by [Simon Sapin, Github account SimonSapin owner, 2011-2023] as part of project WeasyPrint, by [Pallets, Github account pallets owner, 2014-2022] as part of project click, by [mbarkhau, Github account mbarkhau owner, 2019-2021] as part of project markdown-katex, by [Python-Markdown, Github account Python-Markdown owner, 2007-2023] as part of project markdown, by [whi_ne, Github account whinee owner, 2021-2022] as part of project MangDL, and by [whi_ne, Github account whinee owner, 2022] as part of project YAMHL.

All other copyright for project md2pdf are held by [Github Account whinee Owner, 2023].

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

"},{"location":"notes-to-self/","title":"Notes to self","text":"Notes to Self

Look, whi_ne, I have written this for you.

Please, do I humbly plead you, do not ever forgot to read this before pushing changes to Github.

"},{"location":"notes-to-self/#toc","title":"Table of Contents","text":"
  • Versioning System
    • Version Bump Guides
  • Changelog
  • Documentation
"},{"location":"notes-to-self/#versioning-system","title":"Versioning System","text":"

Look, you have made your own versioning system based off semver 2.0.0. Use it properly.

Given a version number user.dev.minor.patch, increment the:

  • user version when you make any changes to the user interface/experience. This does not include improvements on loading times, despite being well within the user experience umbrella.
  • dev version when you make incompatible API changes,
  • minor version when you add functionality in a backwards compatible manner, and
  • patch version when you make backwards compatible bug fixes.

If in doubt, please DO visit semver.org.

"},{"location":"notes-to-self/#versioning-system-version-bump-guides","title":"Version Bump Guides","text":"
  • ANY change in the user interface/experience SHALL induce a user version bump.
  • ANY change in the schema shall induce a dev version bump.
  • ANY change in the documentation SHALL NOT induce any version bump.
flowchart TD\n    VB([Version Bump])\n        VB --> |\"prerelease identifier (pi)\"| e_pr{existing `pi`}\n            e_pr --> |none| bprv(\"bump prerelease version (pv)\")\n                bprv --> ba(bump `pi` to `alpha`)\n                ba --> bp([bump `patch`])\n            e_pr --> |alpha| bb(bump to `beta`)\n                bb --> r0([reset version/s below it to `0` or `none`])\n            e_pr --> |beta| br(bump to `rc`) --> r0\n            e_pr --> |rc| rn(reset to `none`) --> r0\n        VB --> |others| bsv(bump specified version) --> r0
"},{"location":"notes-to-self/#changelog","title":"Changelog","text":"

As used in the changelog, the following types of changes shall have the following implications, of which, their allowed version bumps should be everything, unless explicably stated otherwise:

  • Added for new features.
    • user
    • dev
    • minor
  • Changed for changes in existing functionality.
    • user
    • dev
  • Deprecated for soon-to-be removed features.
    • patch
  • Removed for now removed features.
    • user
    • dev
  • Fixed for any bug fixes.
  • Security in case of vulnerabilities.

Mind the human as you do with the robot. Format the changelog properly. Example format:

## 69.4.2.0 (minor bump)\n\nSprinkle a description here.\n\n### Added\n\n- I added a cool feature.\n\n### Deprecated\n\n- This feature will be deprecated 'cuz I can't maintain it anymore.\n\n### Security\n\n- Fixed stuff where the anilist token is leaked to everyone using this app.\n
"},{"location":"notes-to-self/#documentation","title":"Documentation","text":"

The documentation system is a custom solution.

If the documentation generator fails, check the traceback. It is commonly due to errors in the code and not the generator itself.

Do not blame the shitty generator you wrote. You might just have written a faulty code.

"},{"location":"terms%20of%20usage/","title":"Terms of usage","text":"Terms of Usage and Disclaimers"},{"location":"terms%20of%20usage/#toc","title":"Table of Contents","text":"
  • Defined Terms
  • Terms of Usage
  • Disclaimer
    • Revisions and Errata
    • DMCA and Copyright Infringements
    • The Developer
"},{"location":"terms%20of%20usage/#defined-terms","title":"Defined Terms","text":"

The key words \"MUST\", \"MUST NOT\", \"REQUIRED\", \"SHALL\", \"SHALL NOT\", \"SHOULD\", \"SHOULD NOT\", \"RECOMMENDED\", \"MAY\", and \"OPTIONAL\" in this document are to be interpreted as described in RFC 2119.

As used in this Disclaimer, the following terms SHALL have the following meanings (such meanings to be equally applicable to both the singular and plural forms of the terms defined unless explicably mentioned otherwise):

  • Developer hereby means the person who has developed the Project going by the alias of \"whi~nyaan!\" in the internet, username of \"whinee\" in \"Github\", username of \"whi_ne#4783\" in \"Discord\" and rightful owner of the electronic mail address \"whinyaan@protonmail.com\", only meant to be used in singular form

  • Project hereby means the Open Source Project called \"md2pdf\" developed by the Developer, only meant to be used in singular form

  • Website hereby means a set of interconnected webpages, prepared and maintained as a collection of information for the Project by the Developer, located at m2p.whinyaan.xyz, only meant to be used in singular form; and

  • User hereby means the person who uses this Project and/or Website, regardless of their intentions and attributes including, but not limited to the following:

    age, body size, caste, citizenship, civil status, disability, education, ethnicity, familial status, gender expression, gender identity, genetic information, immigration status, level of experience, nationality, personal appearance, pregnancy, race, religion, sex characteristics, sexual orientation, sexual identity, socio-economic status, tribe, and veteran status

"},{"location":"terms%20of%20usage/#terms-of-usage","title":"Terms of Usage","text":"

As stated in the license agreement, under no circumstance SHALL the Developer of this Project have any liability to the User for any loss or damage of any kind incurred as a result of the use of this Project, even if the Developer or an authorize representative of this Project and/or Website has been notified, orally or written, of the possibility of such damage including, but not limited to the following:

  • Criminal charges due to accessing illegal content where it is banned or prohibited by law; and

  • Damage to device due to usage of the Project and/or Website in said device

Some jurisdiction does not allow limitations on implied warranties or limitations of liability for incidental damages, these limitations MAY not apply to you.

The needy Developer also REQUIRES the Users to pat said developer 3 (three) times a day. Failure to do so MUST revoke the User's rights to use the app.

These Terms of Usage MAY change at any time for any and no reason and it is up to the Users to check for updates from time to time, which means that by no means SHALL the Developer be liable for the User's failure to check the Terms of Usage at a regular basis.

By using the Project and/or the Website, the User agrees and confirms to the license agreement and the Terms of Usage.

"},{"location":"terms%20of%20usage/#disclaimer","title":"Disclaimer","text":"

The Developer only intends to use this Project only for educational purposes.

"},{"location":"terms%20of%20usage/#disclaimer-revisions-and-errata","title":"Revisions and Errata","text":"

The materials and resources in this Website and the Project MAY include technical, typographical, or photographic errors. The Developer does not promise that any of the materials in this Website and the Project are accurate, complete, or current. The said Developer MAY change the materials contained on its Website at any time without notice. The Developer does not make any commitment to update the materials.

"},{"location":"terms%20of%20usage/#disclaimer-dmca-and-copyright-infringements","title":"DMCA and Copyright Infringements","text":"

The contents served by the Project is publicly accessible through the Internet. In case of copyright infringement, please direct the complaints, claims, and possible criminal charges against to the respective file hosts and content providers, not to the Project nor to the Developer, as the Developer is not affiliated with them, at any way, shape or form.

The Project is a program that serves contents like a normal browser do through scraping 3rd-party websites that are publicly accessible via any regular web browser, however it does less requests than a normal browser would, and is sophisticated enough to serve the content how the Developer would want to. It is the responsibility of the Users to avoid any actions that might violate the laws governing their locality.

"},{"location":"terms%20of%20usage/#disclaimer-the-developer","title":"The Developer","text":"

The Project is created in good faith that this will only serve an educational purpose for the Developer and the Users and will only be used for that said purpose.

By no means harassing the Developer including, but not limited to the following, is legal nor ethically and morally correct:

  • Exploiting the undisclosed personal information of the Developer against them, possibly accessed through illegal means, including, but not limited to the following:

    • Physical/Online Stalking

    • Hacking; and

    • Social Engineering

  • Sending threatening messages, mentioning doing physical harm to the Developer or not, attempts to morally degrade the said Developer, including, but not limited to the following ways:

    • Through social media platforms, including but not limited to Discord, Youtube, and Facebook

    • Through e-mail; and

    • Through physical mail

The Developer will act legally against those who have done anything illegal against the said Developer, including, but not limited to the following above.

For any concerns regarding the legality of the Project and/or Websites, begin by creating a new issue or through emailing me at whinyaan@protonmail.com or contacting me in Discord at whi_ne#4783.

"},{"location":"todo/","title":"TODO","text":""},{"location":"todo/#toc","title":"Table of Contents","text":"
  • Legend
    • Tags
  • Todo
  • In Progress
  • Done
"},{"location":"todo/#legend","title":"Legend","text":""},{"location":"todo/#legend-tags","title":"Tags","text":"
  • feat: Feature
"},{"location":"todo/#todo","title":"Todo","text":"
  • [ ] [docs]
  • [ ] [feat] n-column support
  • [ ] [feat] GUI
  • [ ] [feat] Custom Help Function (to only compute help page's width when help is actually called; the CLI is actually already fast enough that this might not be necessary, but is just a mere novelty)
"},{"location":"todo/#in-progress","title":"In Progress","text":"
  • [ ] Custom mermaid.js renderer (will be done after the GUI, as the HUI will be written in JS, and the rendered will be using JS too)
"},{"location":"todo/#done","title":"Done","text":"
  • [x] Custom KaTex renderer (as the best one for Weasyprint use, mbarkhau/markdown-katex is so dang slow)
"},{"location":"docs/","title":"Index","text":"All Version
  • Version 0.x.x.x
"},{"location":"docs/0/","title":"Index","text":"Version 0.x.x.x
  • Version 0.0.x.x
"},{"location":"docs/0/0/","title":"Index","text":"0.0.x.x
  • API Documentation
  • For contributors
"},{"location":"docs/0/0/installation/","title":"Installation","text":"Installating md2pdf"},{"location":"docs/0/0/installation/#toc","title":"Table of Contents","text":"
  • Windows
  • Mac
  • Linux
    • Arch
"},{"location":"docs/0/0/installation/#windows","title":"Windows","text":"
  1. Copy the following text:

    Set-ExecutionPolicy Bypass -Scope Process -Force\n[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072\niex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))\n
  2. Press Win. An interface should pop up as shown below:

  3. Search for settings by typing \"Settings\" in the text field as shown below:

    Press Enter.

  4. A window should pop up as shown below:

    Press \"Apps\" in the selection below.

  5. You should be redirected to \"Apps & Features\" as shown below:

    Below the subtitle \"Apps & Features\", press the hyperlink \"App execution aliases\".

  6. You should be redirected to \"App execution aliases\" as shown below:

    Toggle the \"App installer\" for both \"python.exe\" and \"python3.exe\". Exit the settings app.

  7. Press Windows + R (Press Windows and R keys simultaneously)

  8. A window with a title Run should appear. Focus to the said window in the Open: text field by hovering the mouse towards the said text field and left-clicking the mouse and type powershell as shown below:

  9. Press Ctrl + Shift + Enter (Press Ctrl, Shift, and Enter keys simultaneously).

  10. A window with a title User Account Control should appear as shown below:

  11. Focus to the said window and press the Yes button by hovering the mouse towards the said button and left-clicking the mouse. A window named Administrator: Windows Powershell should pop-up.

  12. Focus to the window named Administrator: Windows Powershell window by hovering the mouse towards the said window and left-clicking the mouse. Then, press Ctrl + V (Press Ctrl and V keys simultaneously).

    If the window Administrator: Windows Powershell seems to hang up, focus to said window by hovering the mouse towards the said window and left-clicking the mouse, then press Enter five times every minute or so until something happens.

  13. Restart your computer, then login to the user account to which you have done the above instructions at.

  14. Copy the following text:

    choco install nodejs -y\nnpm install katex\n
  15. Repeat step 7-12.

  16. [RECOMMENDED] Use Python environment

    It is recommended to use a Python environment to isolate the dependencies installed to the main Python installation which other programs might use, as this will reduce the chance of incompatible dependency version collisions.

    Change directory to where you want to put the Python environment, by replacing the <dir> in the following text to your desired directory in your machine, and copy the text\"

    cd <dir>\npython3 -m venv pyenv\n.\\pyenv\\Scripts\\activate\n

    Repeat step 12.

  17. Copy the following text:

    python3 -m pip install w{{pip}}\n

    And you have installed

"},{"location":"docs/0/0/installation/#mac","title":"Mac","text":"
  1. Open your preferred terminal and run the following command:

    /bin/bash -c \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)\"\n
  2. Next, for OS X 10.13 (High Sierra) or younger, run the following command:

    echo 'export PATH=\"/usr/local/opt/python/libexec/bin:$PATH\"' >> ~/.profile\n

And for OS X 10.12 (Sierra) or older, use the following command instead:

echo 'export PATH=/usr/local/bin:/usr/local/sbin:$PATH' >> ~/.profile\n

  1. Afterwards, install the rest of the prerequisites by running the following command:

    brew install node\n

  2. Then, install katex with npm by running the following command:

    npm install katex\n
"},{"location":"docs/0/0/installation/#linux","title":"Linux","text":""},{"location":"docs/0/0/installation/#linux-arch","title":"Arch","text":"
  1. Open your preferred terminal and run the following command:
    sudo pacman -Syyu --noconfirm curl\n
"},{"location":"docs/0/0/markdown/","title":"Markdown","text":"Markdown Implementation"},{"location":"docs/0/0/markdown/#toc","title":"Table of Contents","text":"
  • Base Implementation
  • Extended Syntax
    • Math Expression
"},{"location":"docs/0/0/markdown/#base-implementation","title":"Base Implementation","text":"

md2pdf uses Python-Markdown/markdown to convert Markdown to HTML which, apparently, is a Python implementation of John Gruber's markdown

According to the cited program's documentation, the specification is implemented as close to the reference specification as possible. In this link, you will see difference of the Python implementation and the original implementation.

And oh yes, this is an arguably messy implementation of Markdown, as opposed to Commonmark Markdown. But we got to make do of what we have, no? baka baka :3

"},{"location":"docs/0/0/markdown/#extended-syntax","title":"Extended Syntax","text":"

md2pdf extended the base implementation, and hereinunder are the details.

"},{"location":"docs/0/0/markdown/#extended-syntax-math-expression","title":"Math Expression","text":"

KaTeX expressions are supported in this program. You just need to surround it in a code block, with the language set as math. An example of this is the following:

```math\n% \\f is defined as #1f(#2) using the macro\n\\f\\relax{x} = \\int_{-\\infty}^\\infty\n    \\f\\hat\\xi\\,e^{2 \\pi i \\xi x}\n    \\,d\\xi\n```\n

This link lists all of the supported functions in KaTeX, grouped logically.

"},{"location":"docs/0/0/api/","title":"src","text":""},{"location":"docs/0/0/api/#sub-modules","title":"Sub-modules","text":"
  • src.cli
  • src.globals
  • src.info
  • src.md_pp
  • src.pdfgenerator
  • src.utils
"},{"location":"docs/0/0/api/cli/","title":"src.cli","text":"Functions hmc
(raw_HTML:\u00a0str, HTML_path:\u00a0str, raw_MD:\u00a0str, MD_path:\u00a0str, hf:\u00a0bool\u00a0|\u00a0None\u00a0=\u00a0None) \u2011> str\n

HTML or Markdown chooser.

Return first argument that is not None and convert it into HTML, if it is not already.

Args:
  • raw_HTML (str): Raw HTML string.
  • HTML_path (str): Path to HTML file.
  • raw_MD (str): Raw Markdown string.
  • MD_path (str): Path to Markdown file.
Returns:

string: Raw HTML string.

mc
(raw_MD:\u00a0str, MD_path:\u00a0str, hf:\u00a0bool\u00a0|\u00a0None\u00a0=\u00a0None) \u2011> str\u00a0|\u00a0None\n

Markdown chooser.

Return first argument that is not None and convert it into HTML.

Args:
  • raw_MD (str): Raw Markdown string.
  • MD_path (str): Path to Markdown file.
Returns:

string: Raw HTML string.

"},{"location":"docs/0/0/api/globals/","title":"src.globals","text":""},{"location":"docs/0/0/api/info/","title":"src.info","text":"Variables

CHOLDER HTML text of copyright holders of this project

PROJECT_NAME Project's name

SVER The current version of the project, compliant with the semver.

This project uses a modified semver. For more information, visit this link.

VARIANT The application variant

This is useful for debugging, and for initializing the application's configuration. Following are the allowed variants:

  • installable: for when the application is packed as an installable application
  • package: for when the application is published on PyPi (as a Python Library)
  • portable: for when the application is packed as a portable application

VLS The current version of the project as a list.

The list consists of 6 integers, which represent the following: - User - Dev - Minor - Patch - Prerelease Identifier The prerelease identifier number corresponds to the following values: 0: alpha 1: beta 2: release candidate or rc 3: none - Prerelease Version

"},{"location":"docs/0/0/api/md_pp/","title":"src.md_pp","text":"Functions get_bin_cmd
() \u2011> list[str]\n
htmlsvg2img
(html:\u00a0str) \u2011> str\n
katex2html
(marker:\u00a0str, tex:\u00a0str) \u2011> tuple[str,\u00a0str]\n
make_marker_id
(text:\u00a0str) \u2011> str\n
mdblocks_katex2img
(mdblocks:\u00a0dict[str,\u00a0str]) \u2011> list[typing.Any]\n
Classes FencedBlockPostprocessor
(md:\u00a0str, ext:\u00a0src.md_pp.WhExtension)\n

Postprocessors are run after the ElementTree it converted back into text.

Each Postprocessor implements a \"run\" method that takes a pointer to a text string, modifies it as necessary and returns a text string.

Postprocessors must extend markdown.Postprocessor.

Ancestors (in MRO)
  • markdown.postprocessors.Postprocessor
  • markdown.util.Processor
Methods run
(self, text:\u00a0str) \u2011> str\n

Subclasses of Postprocessor should implement a run method, which takes the html document as a single text string and returns a (possibly modified) string.

FencedBlockPreprocessor
(md:\u00a0str, ext:\u00a0src.md_pp.WhExtension)\n

Preprocessors are run after the text is broken into lines.

Each preprocessor implements a \"run\" method that takes a pointer to a list of lines of the document, modifies it as necessary and returns either the same pointer or a pointer to a new list.

Preprocessors must extend markdown.Preprocessor.

Ancestors (in MRO)
  • markdown.preprocessors.Preprocessor
  • markdown.util.Processor
Methods run
(self, lines:\u00a0list[str]) \u2011> list[str]\n

Each subclass of Preprocessor should override the run method, which takes the document as a list of strings split by newlines and returns the (possibly modified) list of lines.

WhExtension
(**kwargs:\u00a0dict[str,\u00a0typing.Any])\n

Base class for extensions to subclass.

Initiate Extension and set up configs.

Ancestors (in MRO)
  • markdown.extensions.Extension
Methods extendMarkdown
(self, md:\u00a0markdown.core.Markdown) \u2011> None\n

Add the various processors and patterns to the Markdown Instance.

This method must be overridden by every extension.

Keyword arguments:

  • md: The Markdown instance.

  • md_globals: Global variables in the markdown module namespace.

reset
(self) \u2011> None\n
"},{"location":"docs/0/0/api/pdfgenerator/","title":"src.pdfgenerator","text":"Functions calc_margin
(margin:\u00a0list[float], header_height:\u00a0int, footer_height:\u00a0int) \u2011> str\n
get_element
(boxes, element)\n

Given a set of boxes representing the elements of a PDF page in a DOM-like way, find the box which is named element.

Notes: - When Weasyprint renders an html into a PDF, it goes though several intermediate steps. Here, in this class, we deal mostly with a box representation: 1 Document have 1 Page or more, each Page 1 Box or more. Each box can contain other box. Hence the recursive method get_element for example. For more, visit the following links: - https://weasyprint.readthedocs.io/en/stable/hacking.html#dive-into-the-source - https://weasyprint.readthedocs.io/en/stable/hacking.html#formatting-structure

margin_preprocessor
(margin:\u00a0list[str]) \u2011> list[float]\n
Classes PDFGenerator
(*, main_html:\u00a0str, stylesheets:\u00a0list[str], first_page_header_html=builtins.str, first_page_footer_html=builtins.str, header_html:\u00a0str, footer_html:\u00a0str, base_url:\u00a0str, size:\u00a0str, margin:\u00a0list[str])\n

Generate a PDF out of a rendered template, with the possibility to integrate nicely a header and a footer if provided.

Notes: - Warning: the logic of this class relies heavily on the internal Weasyprint API. This snippet was written at the time of the release 47, it might break in the future. - This generator draws its inspiration and, also a bit of its implementation, from this discussion in the library github issues: https://github.com/Kozea/WeasyPrint/issues/92 - Hello from whi_ne (https://github.com/whinee) in the past, modified slightly at the time of release 51. And yes, I struggled adding my own features.

Initialize PDF Generator.

Notes: - The size and margin arguments are applied to the PDF like CSS does. See https://developer.mozilla.org/en-US/docs/Web/CSS/@page/size and https://developer.mozilla.org/en-US/docs/Web/CSS/margin#syntax respectively for more details.

Args:
  • main_html (str): An HTML file (most of the time a template rendered into a string) which represents the core of the PDF to generate.
  • first_page_header_html (str): Optional HTML for the first page's header.
  • first_page_footer_html (str): Optional HTML for the first page's footer.
  • header_html (str): Optional HTML for header.
  • footer_html (str): Optional HTML for footer.
  • base_url (str): An absolute url to the page which serves as a reference to Weasyprint to fetch assets, required to get our media.
  • stylesheets (list[str]): Optional paths to stylesheets to be used for rendering the PDF.
  • size (str): CSS size property applied directly to each page.
  • margin (str): CSS margin property applied directly to each page.
Methods render_pdf
(self) \u2011> bytes\n

Return the rendered PDF.

Returns:

bytes: The rendered PDF.

"},{"location":"docs/0/0/api/utils/","title":"src.utils","text":""},{"location":"docs/0/0/api/utils/#super-module","title":"Super-module","text":"
  • src
"},{"location":"docs/0/0/api/utils/#sub-modules","title":"Sub-modules","text":"
  • src.utils.base_cli
  • src.utils.base_exc
  • src.utils.cd
  • src.utils.cfg
  • src.utils.exceptions
  • src.utils.style
  • src.utils.types
  • src.utils.utils
"},{"location":"docs/0/0/api/utils/base_cli/","title":"src.utils.base_cli","text":"

Hereunder resides functions for constructing CLI for this program.

This module heavily documents my descent to madness.

An unholy amalgamation of megalamonia, depression, God complex, and impostor syndrome filled my broken heart.

This file is the digital manifestation of my mental woes.

Masochistic tendencies fuelling my coding sessions.

I wish upon this abyss to not touch this file ever again.

whi~nyaan! \u2015 2023

Functions command
(group:\u00a0src.utils.base_cli.Group) \u2011> Callable[[Callable[...,\u00a0Any]],\u00a0Callable[...,\u00a0Any]]\n

Wrapper for click commands.

Args:
  • group (Group): Command group of the command to be under.
Returns:
  • Callable[[Callable[..., Any]], Callable[..., Any]]
command_group
(name:\u00a0Union[str,\u00a0Callable[...,\u00a0Any],\u00a0ForwardRef(None)]\u00a0=\u00a0None, **attrs:\u00a0Any) \u2011> src.utils.base_cli.Group\n
custom_command
(name:\u00a0Union[str,\u00a0Callable[...,\u00a0Any],\u00a0ForwardRef(None)]\u00a0=\u00a0None, cls:\u00a0Optional[Type[src.utils.base_cli.Command]]\u00a0=\u00a0None, **attrs:\u00a0Any) \u2011> Union[src.utils.base_cli.Command,\u00a0Callable[...,\u00a0src.utils.base_cli.Command]]\n
de_rcfg
() \u2011> src.utils.cd.CustomDict\n

Return parsed configuration file, fetched from the CFLOP.

Returns:

dict[Any, Any]: description

de_wcfg
(value:\u00a0dict[typing.Any,\u00a0typing.Any]\u00a0|\u00a0list[typing.Any]) \u2011> None\n

Write given value to the configuration file, fetched from the CFLOP.

Args:
  • value (dict[Any, Any] | list[Any]): dictionary to overwrite the configuration file, fetched from the CFLOP.
get_stg
(path:\u00a0str, **kwargs:\u00a0dict[str,\u00a0typing.Any]) \u2011> Optional[Any]\n
init
(idx:\u00a0int) \u2011> None\n
select
(message:\u00a0str, choices:\u00a0Union[Sequence[str\u00a0|\u00a0questionary.prompts.common.Choice\u00a0|\u00a0dict[str,\u00a0Any]],\u00a0dict[str,\u00a0Any]], default:\u00a0Optional[Any]\u00a0=\u00a0None, instruction:\u00a0str\u00a0|\u00a0None\u00a0=\u00a0None, qmark:\u00a0str\u00a0|\u00a0None\u00a0=\u00a0None, pointer:\u00a0str\u00a0|\u00a0None\u00a0=\u00a0None, style:\u00a0Optional[prompt_toolkit.styles.base.BaseStyle]\u00a0=\u00a0None, show_selected:\u00a0bool\u00a0|\u00a0None\u00a0=\u00a0None, ret_err:\u00a0bool\u00a0|\u00a0None\u00a0=\u00a0None, **kwargs:\u00a0dict[str,\u00a0typing.Any]) \u2011> tuple[bool,\u00a0typing.Any]\n
Classes Command
(name:\u00a0str\u00a0|\u00a0None, context_settings:\u00a0Optional[Dict[str,\u00a0Any]]\u00a0=\u00a0None, callback:\u00a0Optional[Callable[...,\u00a0Any]]\u00a0=\u00a0None, params:\u00a0Optional[List[ForwardRef('Parameter')]]\u00a0=\u00a0None, help:\u00a0str\u00a0|\u00a0None\u00a0=\u00a0None, epilog:\u00a0str\u00a0|\u00a0None\u00a0=\u00a0None, short_help:\u00a0str\u00a0|\u00a0None\u00a0=\u00a0None, options_metavar:\u00a0str\u00a0|\u00a0None\u00a0=\u00a0'[OPTIONS]', add_help_option:\u00a0bool\u00a0=\u00a0True, no_args_is_help:\u00a0bool\u00a0=\u00a0False, hidden:\u00a0bool\u00a0=\u00a0False, deprecated:\u00a0bool\u00a0=\u00a0False)\n

Commands are the basic building block of command line interfaces in Click. A basic command handles command line parsing and might dispatch more parsing to commands nested below it.

:param name: the name of the command to use unless a group overrides it. :param context_settings: an optional dictionary with defaults that are passed to the context object. :param callback: the callback to invoke. This is optional. :param params: the parameters to register with this command. This can be either :class:Option or :class:Argument objects. :param help: the help string to use for this command. :param epilog: like the help string but it's printed at the end of the help page after everything else. :param short_help: the short help to use for this command. This is shown on the command listing of the parent command. :param add_help_option: by default each command registers a --help option. This can be disabled by this parameter. :param no_args_is_help: this controls what happens if no arguments are provided. This option is disabled by default. If enabled this will add --help as argument if no arguments are passed :param hidden: hide this command from help outputs.

:param deprecated: issues a message indicating that the command is deprecated.

.. versionchanged:: 8.1 help, epilog, and short_help are stored unprocessed, all formatting is done when outputting help text, not at init, and is done even if not using the @command decorator.

.. versionchanged:: 8.0 Added a repr showing the command name.

.. versionchanged:: 7.1 Added the no_args_is_help parameter.

.. versionchanged:: 2.0 Added the context_settings parameter.

Ancestors (in MRO)
  • click.core.Command
  • click.core.BaseCommand
Methods get_help_option
(self, ctx:\u00a0click.core.Context) \u2011> Optional[click.core.Option]\n

Returns the help option object.

Group
(name:\u00a0str\u00a0|\u00a0None\u00a0=\u00a0None, commands:\u00a0Union[Dict[str,\u00a0click.core.Command],\u00a0Sequence[click.core.Command],\u00a0ForwardRef(None)]\u00a0=\u00a0None, **attrs:\u00a0Any)\n

A group allows a command to have subcommands attached. This is the most common way to implement nesting in Click.

:param name: The name of the group command. :param commands: A dict mapping names to :class:Command objects. Can also be a list of :class:Command, which will use :attr:Command.name to create the dict. :param attrs: Other command arguments described in :class:MultiCommand, :class:Command, and :class:BaseCommand.

.. versionchanged:: 8.0 The commmands argument can be a list of command objects.

Ancestors (in MRO)
  • click.core.Group
  • click.core.MultiCommand
  • click.core.Command
  • click.core.BaseCommand
Methods command
(self, *args:\u00a0Any, **kwargs:\u00a0Any) \u2011> Union[Callable[[Callable[...,\u00a0Any]],\u00a0src.utils.base_cli.Command],\u00a0src.utils.base_cli.Command]\n

A shortcut decorator for declaring and attaching a command to the group. This takes the same arguments as :func:command and immediately registers the created command with this group by calling :meth:add_command.

To customize the command class used, set the :attr:command_class attribute.

.. versionchanged:: 8.1 This decorator can be applied without parentheses.

.. versionchanged:: 8.0 Added the :attr:command_class attribute.

cao
(group:\u00a0src.utils.base_cli.Group)\n

Returns wrappers for a click command evaluated from the given arguments.

Initialize object.

Args:
  • group (Group): Command group of the command to be under.
Methods arguments
(self) \u2011> Callable[[Callable[...,\u00a0Any]],\u00a0Callable[...,\u00a0Any]]\n

The arguments wrapper.

Returns:

Callable[[Callable[..., Any]], Callable[..., Any]]

command
(self) \u2011> Callable[[Callable[...,\u00a0Any]],\u00a0Callable[...,\u00a0Any]]\n

The command wrapper.

Returns:

Callable[[Callable[..., Any]], Callable[..., Any]]

kwargs_preprocessor
(self, func:\u00a0Callable[...,\u00a0Any]) \u2011> Callable[...,\u00a0Any]\n
option_the
(self, maxlen_type_string:\u00a0int, maxlen_opts_help:\u00a0int) \u2011> Callable[...,\u00a0tuple[str,\u00a0str,\u00a0str]]\n
options
(self) \u2011> Callable[[Callable[...,\u00a0Any]],\u00a0Callable[...,\u00a0Any]]\n

The options wrapper.

My God in heaven, I'm agnostic, but please save me from all evil. Amen.

Returns:

Callable[[Callable[..., Any]], Callable[..., Any]]

wrap
(self, func:\u00a0Callable[...,\u00a0Any]) \u2011> Callable[...,\u00a0Any]\n

Wrap given function with corresponding click decorators.

Args:
  • func (Callable[..., Any]): Function to be wrapped.
Returns:

Callable[..., Any]: Wrapped function.

"},{"location":"docs/0/0/api/utils/base_exc/","title":"src.utils.base_exc","text":"Functions c_exc
(cls:\u00a0Type[BaseException]) \u2011> Type[BaseException]\n

Decorator to raise a custom exception.

This function gives the class an init function that raises the exception. If the class does not inherit from any Exception, it will be automatically inherit from Exception. This function also wraps the Exception with c_exc_str method, for adding the __str__ method.

Args:
  • cls (BaseException | Object): The exception to modify.
Returns:

BaseException: The exception to raise.

c_exc_str
(cls:\u00a0Type[BaseException]) \u2011> Type[BaseException]\n

Decorator to add the str method to an exception.

Args:
  • cls (BaseException): The exception to add the str method to.
Returns:

BaseException: The exception to raise.

"},{"location":"docs/0/0/api/utils/cd/","title":"src.utils.cd","text":"Functions test
() \u2011> None\n
Classes BEHAVIOR
(value, names=None, *, module=None, qualname=None, type=None, start=1)\n

An enumeration.

Ancestors (in MRO)
  • enum.Enum
Class variables

append

insert

modify

CustomDict
(*args, **kwargs)\n

Custom dictionary.

Ancestors (in MRO)
  • builtins.dict
Methods dir
(self, path:\u00a0str\u00a0=\u00a0'c0VjUmVUX2NPZEUgYnkgd2hpX25l', de:\u00a0Any\u00a0=\u00a0'c0VjUmVUX2NPZEUgYnkgd2hpX25l', sep:\u00a0str\u00a0=\u00a0'/') \u2011> Any\n
traverse
(self, path:\u00a0str, elem:\u00a0Union[dict[str,\u00a0Any],\u00a0Sized], sep:\u00a0str, idx:\u00a0int\u00a0=\u00a00, og_path:\u00a0str\u00a0|\u00a0None\u00a0=\u00a0None) \u2011> Union[tuple[int,\u00a0Union[Any,\u00a0dict[str,\u00a0int]]],\u00a0Any]\n

summary.

Return States | State || Return Type || Description | |--------:|-------------------------------------------:|:----------------------------------| | 0 || Any (Indexed Item) || Path fully traversed | | 1 || dict[str, int] (Kwargs for CDKeyError) || Path's not in element | | 2 || dict[str, int] (Kwargs for CDIndexError) || Path's current index not in range |

Callback States | State || Arguments Type || Description | |--------:|---------------------------------------------:|:-------------------------------------------| | 0 || dict (Indexed Item), str (key), int (idx) || Path fully traversed; Element type dict | | 1 || Sized (Indexed Item), int (key), int (idx) || Path fully traversed; Element type Sized |

Args:
path (str): _description_\nelem (dict[str, Any] | Sized): _description_\nsep (str): _description_\nidx (int, optional): _description_. Defaults to 0.\nog_path (Optional[str], optional): _description_. Defaults to None.\n
Raises:
CDKeyError: _description_\nCDKeyError: _description_\nCDKeyError: _description_\nCDIndexError: _description_\nCDTypeError: _description_\n
Returns:
Any: _description_\n
flowchart TD\n    start([start]) --> args[/path, value, elem/] --> a\n    a{elem isDict?}\n        a --> |yes| b{key in<br>elem}\n            b --> |yes| c{path fully<br>traversed?}\n                c -->\n|no| y[[\"traverse(<br>path=path[1:],<br>elem=elem[key]<br>)\"]]:::success\n                c --> |yes| x[/\"(0, elem[key])\"/]:::success\n            b --> |no| f([CDKeyError]):::error\n        a --> |no| g{elem isSized?}\n            g --> |no| l([\"CDTypeError;<br>exp dict/Sized\"]):::error\n                h --> |no| m([\"CDKeyError;<br>key empty\"]):::error\n                    i --> |no| n([\"CDKeyError;<br>key not int\"]):::error\n            g --> |yes| h{\"key notEmpty?\"}\n                h --> |yes| i{key int?}\n                    i --> |yes| j{key inRange?}\n                        j -->\n|no| w[/\"(1, {'idx': idx, 'ls_idx': ls_idx, 'len_iter': len_iter})\"/]:::success\n                        j ----> |yes| c\n\n    classDef success color:#83ce9e,stroke:#6fc890\n    classDef error color:#f3626b,stroke:#f14651
"},{"location":"docs/0/0/api/utils/cfg/","title":"src.utils.cfg","text":"Functions dcfg
(value:\u00a0dict[str,\u00a0typing.Any], ext:\u00a0str) \u2011> str\n

Dump the given value to a string with the given extension.

Args:
  • value (dict): Value to dump to a string.
  • ext (str): Extension to dump the value to.
Returns:

str: The dumped value.

pcfg
(d:\u00a0str, type:\u00a0str) \u2011> src.utils.cd.CustomDict\n

Parse the given string as the given type.

Args:
  • d (str): String to parse.
  • type (str): Type to parse the string as.
Returns:

CustomDict: The parsed string.

rcfg
(file:\u00a0str) \u2011> src.utils.cd.CustomDict\n

Read the contents of a file with the given file name.

Args:
  • file (str): File name of the file to read the contents of.
Returns:

CustomDict: The contents of the file.

wcfg
(file:\u00a0str, value:\u00a0dict[typing.Any,\u00a0typing.Any]\u00a0|\u00a0list[typing.Any]) \u2011> None\n

Write the given value to a file with the given file name.

Args:
  • file (str): File name of the file to write the value to.
  • value (dict[Any, Any] | list[Any]): Value to write to the file.
Classes ExtensionNotSupported
(*args:\u00a0list[typing.Any], **kwargs:\u00a0dict[str,\u00a0typing.Any])\n

Method or function hasn't been implemented yet.

Ancestors (in MRO)
  • builtins.NotImplementedError
  • builtins.RuntimeError
  • builtins.Exception
  • builtins.BaseException
"},{"location":"docs/0/0/api/utils/exceptions/","title":"src.utils.exceptions","text":"

Common exceptions are raised if an error occured and it is of the Common exception's common variant of error.

Classes CDExceptions
()\n
Class variables

API

Internals

CLIExceptions
()\n
Class variables

TerminalTooThin Common base class for all non-exit exceptions.

ValidationError

GeneralExceptions
()\n
Class variables

PrerequisiteNotFound

ValidationError

KatexExceptions
()\n
Class variables

NotFound Common base class for all non-exit exceptions.

"},{"location":"docs/0/0/api/utils/style/","title":"src.utils.style","text":"Variables

COLORS t1: F3F78D t2: FF8D5C t3: E84855 t4: B56B45 t5: 404E7C t6: 55828B t7: 4E8098

Functions pp
(t:\u00a0Any, ca:\u00a0bool\u00a0|\u00a0None\u00a0=\u00a0None, *args:\u00a0list[typing.Any], **kwargs:\u00a0dict[str,\u00a0typing.Any]) \u2011> None\n

Center rich printable objects, then pretty print it.

Args:
  • t (Any): Rich printable object to be centered, then pretty printed.
  • ca (bool, optional): Determines whether to center text in the group individually. Defaults to None.
split_text
(t:\u00a0str) \u2011> list[str]\n
text
(t:\u00a0str, *args:\u00a0list[typing.Any], ca:\u00a0bool\u00a0|\u00a0None\u00a0=\u00a0None, **kwargs:\u00a0dict[str,\u00a0typing.Any]) \u2011> rich.console.Group\n
Classes C
()\n
Class variables

h0

h1

h2

s0

s1

s2

S
()\n
Class variables

p0

p1

p_critical

p_error

p_warning

t0

t1

t2

t3

t4

t5

t6

t_critical

t_error

t_good

t_warning

ct
()\n
Static methods group
(*ls:\u00a0rich.console.ConsoleRenderable\u00a0|\u00a0rich.console.RichCast\u00a0|\u00a0str) \u2011> rich.console.Group\n

Group given list of rich printable objects.

Returns:

Group: Group of rich printable objects

table
(cols:\u00a0list[str], rows:\u00a0list[list[str]]) \u2011> None\n

Print table from given list of str and list of list of strings for the columns and rows respectively.

Args:
  • cols (list[str]): List of string for column labels.
  • rows (list[list[str]]): List of rows (list of strings).
"},{"location":"docs/0/0/api/utils/types/","title":"src.utils.types","text":""},{"location":"docs/0/0/api/utils/utils/","title":"src.utils.utils","text":"Functions dnrp
(file:\u00a0str, n:\u00a0Optional[int]\u00a0=\u00a0None) \u2011> str\n

Get the directory component of a pathname by n times recursively then return it.

Args:
  • file (str): File to get the directory of.
  • n (Optional[int], optional): Number of times to get up the directory???? Defaults to 1.
Returns:

str: The directory component got recursively by n times from the given pathname

dpop
(d:\u00a0dict[typing.Any,\u00a0typing.Any], pop:\u00a0list[int\u00a0|\u00a0list[str\u00a0|\u00a0int\u00a0|\u00a0tuple[str,\u00a0...]]\u00a0|\u00a0str], de:\u00a0Optional[Any]\u00a0=\u00a0None) \u2011> Any\n

Iterate through the preferred order of precedence (pop) and see if the value exists in the dictionary. If it does, return it. If not, return de.

Args:
  • d (Dict[Any, Any]): Dictionary to retrieve the value from.
  • pop (list[int | tuple[str | int | tuple] | str]): List of keys to iterate through.
  • de (Any, optional): Default object to be returned. Defaults to None.
Returns:

Any: Retrieved value.

dt
(dt:\u00a0str, format:\u00a0str) \u2011> str\n

Remove timezone from datetime and format it to ISO 8601 format.

Args:
  • dt (str): Unformatted datetime string to be formatted to ISO 8601 format
  • format (str): The initial format of the datetime string
Returns:

str: Formatted datetime string

dt_ts
(ts:\u00a0str) \u2011> str\n

Convert the given unix timestamp to ISO 8601 format.

Args:
  • ts (str): unix timestamp to be converted to ISO 8601 format
Returns:

str: Formatted datetime string

file_exists
(fp:\u00a0str) \u2011> str\n

Check if the given file path exists.

Args:
  • fp (str): File path to check if it exists.
Raises:
  • exceptions.GeneralExceptions.ValidationError.FileNotFound: Raised when a file in the path is not found.
Returns:

str: Return fp when file path exists.

fill_ls
(*, ls:\u00a0Sequence[Any], length:\u00a0int, filler:\u00a0Optional[Any]\u00a0=\u00a0None) \u2011> Sequence[Any]\n

Fill given list (ls) with filler up to length.

Args:
  • ls (types.SequenceAny): List to fill with filler up to length
  • length (int): Length of the list to achieve.
  • filler (Optional[Any], optional): Filler to use. Defaults to None.
Returns:

types.SequenceAny: Filled list.

inmd
(p:\u00a0str, ls:\u00a0Optional[list[str]]\u00a0=\u00a0None) \u2011> str\n

\"If Not os.path.isdir, Make Directories\".

Args:
  • p (str): The path to be created, if it does not exist.
  • ls(Optional[list[str]], optional): List to append directories to that are not found and successfully created. Defaults to None.
Returns:

str: The path given.

iter_ls_with_items
(ls:\u00a0list[typing.Any], *items:\u00a0list[typing.Any]) \u2011> Generator[tuple[Any,\u00a0...],\u00a0None,\u00a0None]\n
ivnd
(var:\u00a0Any, de:\u00a0Any) \u2011> Any\n

If Var is None, return Default else var.

Args:
  • var (Any): Variable to check if it is None.
  • de (Any): Default value to return if var is None.
Returns:

Any: var if var is not None else de.

le
(expr:\u00a0str) \u2011> Any\n

Literal Evaluation.

Args:
  • expr (str): Expression to be evaluated.
Returns:

Any: Expression literally evaluated.

noop
(*args:\u00a0list[typing.Any], **kwargs:\u00a0dict[str,\u00a0typing.Any]) \u2011> None\n

No operation.

noop_single_kwargs
(arg:\u00a0Any) \u2011> Any\n
repl
(s:\u00a0str, repl_dict:\u00a0dict[str,\u00a0list[str]]) \u2011> str\n

Iterate through the dictionary, find the values in the given string and replace it with the corresponding key, and output the modified string.

Args:
  • s (str): String to modify.
  • repl_dict (dict[str, list[str]]): key-value pairs to replace string within the given string.
Returns:

str: Modified string.

rfnn
(*args:\u00a0list[typing.Any]) \u2011> Any\n

Return First Non-None.

Return the first argument that is not None, else return None.

Returns:

Any: The first argument that is not None, else None.

run_mp
(func:\u00a0Callable[...,\u00a0Any], iterable:\u00a0Iterable[Any]) \u2011> list[typing.Any]\n
run_mp_qgr
(func:\u00a0Callable[...,\u00a0Any], iterable:\u00a0Iterable[Any]) \u2011> tuple[None]\u00a0|\u00a0tuple[typing.Any]\u00a0|\u00a0tuple[typing.Any,\u00a0...]\n
run_mp_qir
(func:\u00a0Callable[...,\u00a0Any], iterable:\u00a0Iterable[Any], callback:\u00a0Callable[...,\u00a0Any]) \u2011> None\n

Run multiprocessing.Pool().map_async(), and quit in return.

Iterate over iterable and apply iterated item to func asynchronously. Wait for a single process in the pool to return, and terminate the pool.

This function requires the given function to return a bool, or an iterable with its first item as a bool. This bool is then used to decide whether to trigger the callback and terminate the pool.

run_mp_star
(func:\u00a0Callable[...,\u00a0Any], iterable:\u00a0Iterable[Iterable[Any]]) \u2011> list[typing.Any]\n
run_mp_star_qgr
(func:\u00a0Callable[...,\u00a0Any], iterable:\u00a0Iterable[Iterable[Any]]) \u2011> tuple[None]\u00a0|\u00a0tuple[typing.Any]\u00a0|\u00a0tuple[typing.Any,\u00a0...]\n
run_mp_star_qir
(func:\u00a0Callable[...,\u00a0Any], iterable:\u00a0Iterable[Iterable[Any]], callback:\u00a0Callable[...,\u00a0Any]) \u2011> None\n

Run multiprocessing.Pool().starmap_async(), and quit in return.

Iterate over iterable and apply iterated items to func asynchronously. Wait for a single process in the pool to return, and terminate the pool.

sanitize_text
(s:\u00a0str) \u2011> str\n

Sanitize input text.

Reference: https://stackoverflow.com/a/93029

Args:
  • s (str): Text to be sanitized.
Returns:

str: Sanitized text.

squery
(query:\u00a0str, possibilities:\u00a0list[str], cutoff:\u00a0int\u00a0|\u00a0float\u00a0=\u00a00.6, *, processor:\u00a0Callable[[Any],\u00a0Any]\u00a0=\u00a0<function <lambda>>) \u2011> Generator[tuple[None,\u00a0str]\u00a0|\u00a0tuple[float,\u00a0str],\u00a0None,\u00a0None]\n

Custom search query.

Args:
  • query (str): String to search for in the possibilities.
  • possibilities (list[str]): The possibilities to search from.
  • cutoff (int | float, optional): The minimum percentage of similarity from the given possibilities. Defaults to 0.6.
  • processor (Callable[[Any], Any], optional): Processes the possibilities before comparing it with the query. Defaults to lambda x: x.
Returns:

Generator[tuple[None, str] | tuple[float, str], None, None]: Generator object of mastching search quries.

str2int
(s:\u00a0str) \u2011> Optional[int]\n

If given string is decimal, convert string to integer, else return False.

Args:
s (str): string to convert to integer.\n
Returns:
bool: _description_\n
which_ls
(cmd:\u00a0str, mode:\u00a0Optional[int]\u00a0=\u00a01, path:\u00a0str\u00a0|\u00a0None\u00a0=\u00a0'/home/whine/whi_ne/3/projects/personal/tools/md2pdf-rewrite/pyenv/bin:/home/whine/bin:/home/whine/whi_ne/2/.local:/home/whine/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl:/var/lib/snapd/snap/bin') \u2011> Union[tuple[str],\u00a0tuple[str,\u00a0...],\u00a0ForwardRef(None)]\n

Given a command, mode, and a PATH string, return the path which conforms to the given mode on the PATH, or None if there is no such file.

Notes: - Yoinked from shutil. - mode defaults to os.F_OK | os.X_OK. path defaults to the result of os.environ.get(\"PATH\"), or can be overridden with a custom search path.

Args:
  • cmd (str): Executable to look for.
  • mode (Optional[int], optional): Executable permissions to look for. Defaults to os.F_OK | os.X_OK.
  • path (Optional[str], optional): The PATH to where the executable can be found. Defaults to os.environ.get(\"PATH\", None).
Returns:

Optional[types.TupleStr]: List of path where executable is found at.

Classes CallbackGetResult
()\n
Methods callback
(self, *args:\u00a0list[typing.Any]) \u2011> None\n
get
(self) \u2011> tuple[None]\u00a0|\u00a0tuple[typing.Any,\u00a0...]\n
ExtInquirerControl
(choices:\u00a0Sequence[Union[str,\u00a0questionary.prompts.common.Choice,\u00a0Dict[str,\u00a0Any]]], default:\u00a0Union[str,\u00a0questionary.prompts.common.Choice,\u00a0Dict[str,\u00a0Any],\u00a0ForwardRef(None)]\u00a0=\u00a0None, pointer:\u00a0str\u00a0|\u00a0None\u00a0=\u00a0'\u00bb', use_indicator:\u00a0bool\u00a0=\u00a0True, use_shortcuts:\u00a0bool\u00a0=\u00a0False, show_selected:\u00a0bool\u00a0=\u00a0False, use_arrow_keys:\u00a0bool\u00a0=\u00a0True, initial_choice:\u00a0Union[str,\u00a0questionary.prompts.common.Choice,\u00a0Dict[str,\u00a0Any],\u00a0ForwardRef(None)]\u00a0=\u00a0None, **kwargs:\u00a0Any)\n

Control that displays formatted text. This can be either plain text, an :class:~prompt_toolkit.formatted_text.HTML object an :class:~prompt_toolkit.formatted_text.ANSI object, a list of (style_str, text) tuples or a callable that takes no argument and returns one of those, depending on how you prefer to do the formatting. See prompt_toolkit.layout.formatted_text for more information.

(It's mostly optimized for rather small widgets, like toolbars, menus, etc...)

When this UI control has the focus, the cursor will be shown in the upper left corner of this control by default. There are two ways for specifying the cursor position:

  • Pass a get_cursor_position function which returns a Point instance with the current cursor position.

  • If the (formatted) text is passed as a list of (style, text) tuples and there is one that looks like ('[SetCursorPosition]', ''), then this will specify the cursor position.

Mouse support:

The list of fragments can also contain tuples of three items, looking like:\n(style_str, text, handler). When mouse support is enabled and the user\nclicks on this fragment, then the given handler is called. That handler\nshould accept two inputs: (Application, MouseEvent) and it should\neither handle the event or return `NotImplemented` in case we want the\ncontaining Window to handle this event.\n

:param focusable: bool or :class:.Filter: Tell whether this control is focusable.

:param text: Text or formatted text to be displayed. :param style: Style string applied to the content. (If you want to style the whole :class:~prompt_toolkit.layout.Window, pass the style to the :class:~prompt_toolkit.layout.Window instead.) :param key_bindings: a :class:.KeyBindings object. :param get_cursor_position: A callable that returns the cursor position as a Point instance.

Ancestors (in MRO)
  • questionary.prompts.common.InquirerControl
  • prompt_toolkit.layout.controls.FormattedTextControl
  • prompt_toolkit.layout.controls.UIControl
Class variables

answer_text

ExtQuestion
(application:\u00a0Application[Any])\n

A question to be prompted.

This is an internal class. Questions should be created using the predefined questions (e.g. text or password).

Ancestors (in MRO)
  • questionary.question.Question
Class variables

kbi

Methods ask
(self, patch_stdout:\u00a0bool\u00a0|\u00a0None\u00a0=\u00a0None, **kwargs:\u00a0dict[str,\u00a0typing.Any]) \u2011> tuple[bool,\u00a0typing.Any]\n

Ask the question synchronously and return user response.

Args:
  • patch_stdout (bool, optional): Ensure that the prompt renders correctly if other threads are printing to stdout. Defaults to None.
Returns:

Any: The answer from the question.

PoolTerminate
(pool:\u00a0multiprocessing.pool.Pool, callback:\u00a0Callable[...,\u00a0Any])\n
Methods inner
(self, err:\u00a0bool, *args:\u00a0list[typing.Any], **kwargs:\u00a0dict[str,\u00a0typing.Any]) \u2011> None\n
"},{"location":"docs/0/0/contribute/","title":"Index","text":"For Contributors
  • Translating md2pdf
"},{"location":"docs/0/0/contribute/translations/","title":"Translations","text":"Translations"},{"location":"docs/0/0/contribute/translations/#toc","title":"Table of Contents","text":"
  • Summary
  • Definition of Terms
  • Translation Directory
  • Notes for Translators
    • Rule of Thumb
    • Variables
  • Translation File
    • Structure
      • metadata
        • version
          • For The Author
          • For The Translators
        • contributors
          • name
          • desc
          • links
            • anilist
            • discord
            • email
            • github
            • reddit
            • twitter
      • splash
        • str
        • desc
        • tln
      • text
        • {scope}
          • {class}
            • {key}
              • str
              • desc
              • tln
"},{"location":"docs/0/0/contribute/translations/#summary","title":"Summary","text":"

While there are no future plans for expanding to the global audience, of which most does not speak English, this application is ready for internationalization.

"},{"location":"docs/0/0/contribute/translations/#definition-of-terms","title":"Definition of Terms","text":"

i18n (abbreviation, numeronym): stands for internationalization; process of designing a software application so that it can be adapted to various languages and regions without engineering changes

"},{"location":"docs/0/0/contribute/translations/#translation-directory","title":"Translation Directory","text":"

The files that contain the translations can be located at ./dev/constants/version/{u}/{d}/lang/

whereas:

  • {u} refers to the user version that uses the constants under this directory
  • {d} refers to the dev version that uses the constants under this directory
Notes: For more information, visit the notes for whi~nyaan!."},{"location":"docs/0/0/contribute/translations/#notes-for-translators","title":"Notes for Translators","text":"

For those who want to translate this application, please read all of the following text.

"},{"location":"docs/0/0/contribute/translations/#notes-for-translators-rule-of-thumb","title":"Rule of Thumb","text":"

This is written by the author with no consideration for other languages. And as such, recommendations and suggestions are highly appreciated.

  • Any technical terminologies should be left untranslated, unless noted by the author (developer) otherwise.
  • Any technical phrase that cannot be translated properly to the target language should be translated without oversimplifying; Oversimplification might lead to a misunderstanding
  • Unless the tone affects the meaning of the text or unless stated otherwise, translators should not preserve the author's tone and should translate it with a neutral tone
"},{"location":"docs/0/0/contribute/translations/#notes-for-translators-variables","title":"Variables","text":"

You might see a text that is enclosed in a bracket, like the following:

{version}\n

These are variables, and are replaced with information in the application before displaying them to the user.

So, our example would be displayed to the users as such:

69.4.20\n

As you can see, it is crucial for displaying information to the users.

When translating a piece of text, make sure to put these variables in an appropriate place, and do not translate its name.

As an example, we will translate this English text:

Thank you for using {app_name}!\n

To Tagalog:

Sa paggamit ng {app_name}, ako ay taos-pusong nagpapasalamat sa iyong pagtangkilik!\n

The variable's name is not translated.

In this next example, the variable is already in a fixed position:

{app_name} version: {version}\n

The Tagalog translation should look like this:

bersyon ng {app_name}: {version}\n

The app_name variable changed places to translate properly. However, there is no need for version to do so, as it is formatted.

"},{"location":"docs/0/0/contribute/translations/#translation-file","title":"Translation File","text":"

A translation file can be found under the translation directory.

Whereas, its name is ISO 639-1 language code that corresponds to its contained translations.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure","title":"Structure","text":""},{"location":"docs/0/0/contribute/translations/#translation-file-structure-metadata","title":"metadata","text":"

Metadata of the translation.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-metadata-version","title":"version","text":"

Version of the translation.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-metadata-version-for-the-author","title":"For The Author","text":"

Given a version number major.minor.patch, bump the:

  • major version when you make a significant change in the contents of a text or the description along side it, that you think it warrants a change in all of the translations.

  • minor version when you make a change in the contents of a text or the description along side it, which does not warrant a change in all of the translations. Example are modifying text to use much more understandable words.

  • patch version when you fix a typographical error in a text. This might induce a change in other translation, but does not warrant otherwise.

Changing the schema, or any key names shall warrant a dev version bump for the application. You break the english text for this application, you fix every other translation.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-metadata-version-for-the-translators","title":"For The Translators","text":"

As the app is written in English, follow the latest version of the english text.

The translation will be bumped as per the specification written here.

If you updated your translations to match that of the current English translation, change the version to the current version of the English translation.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-metadata-contributors","title":"contributors","text":"

List of translation contributors' information, for attribution purposes.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-metadata-contributors-name","title":"name","text":"

Name of the contributor.

It can be an alias, nickname, or a full name. As long as you are happy with being credited using that name, I have no problem with it.

Obscene and/or offensive names however will be apprehended. Otherwise, be creative.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-metadata-contributors-desc","title":"desc","text":"

Describe yourself.

If you're getting credited, go all out. You can even advertise your personal project. As long as the contents are not obscene or offensive, I'm fine with it.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-metadata-contributors-links","title":"links","text":"

Dictionary of links to your contacts, social media, and whatnot.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-metadata-contributors-links-anilist","title":"anilist","text":"

Anilist username.

Example:

anilist: whinyaan\n

Links to https://anilist.co/user/whinyaan.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-metadata-contributors-links-discord","title":"discord","text":"

Key-value pairs of Discord tag and their snowflake.

Example:

discord:\nwhi_ne#4783:\n848092597822160907\n

Links to whi_ne#4783.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-metadata-contributors-links-email","title":"email","text":"

List of electronic mail addresses.

Example:

email:\n- whinyaan@protonmail.com\n

Links to whinyaan@protonmail.com.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-metadata-contributors-links-github","title":"github","text":"

Github username.

Example:

github: whinee\n

Links to https://github.com/whinee.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-metadata-contributors-links-reddit","title":"reddit","text":"

Reddit username.

Example:

reddit: whi-nyaan\n

Links to https://reddit.com/user/whi-nyaan.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-metadata-contributors-links-twitter","title":"twitter","text":"

Twitter username.

Example:

twitter: whi_nyaan\n

Links to https://twitter.com/whi_nyaan.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-splash","title":"splash","text":"

Dictionary of random stuff to be displayed at startup of the application.

Example:

music_artist_rec:\n    str: Listen to Kanro! https://kanromusic.com\n    desc: Author's music artist recommendation\n
"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-splash-str","title":"str","text":"

The actual splash message.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-splash-desc","title":"desc","text":"

Description of the splash message. Might be useful to keep the translation accurate at an acceptable margin. Will not be displayed.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-splash-tln","title":"tln","text":"

Stands for translators' notes, used by translators to describe to the next translators any compromises done to translate the text to a certain language, or whatnot.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-text","title":"text","text":"

Dictionary of scopes, classes, and keys (dictionary) of text to display in the application.

Example:

cli:\n    init:\n        choose_language:\n            str: Choose language\n            desc: |-\n                Choose app language\n
"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-text-scope","title":"{scope}","text":"

There are three scopes allowed, but only the first two are applicable:

  • common
  • cli
  • gui

The first scope is class of keys that can be used in both the CLI and GUI versions of the app. This includes the description and motto of the program, prompts like yes or no, and whatnot. The rest is self-explanatory.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-text-scope-class","title":"{class}","text":"

This is where keys are categorized. For example, keys that convey information regarding the application can be put under the info class, while the keys that are used for prompting the users can be put under the prompt class.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-text-scope-class-key","title":"{key}","text":"

This is the name of the key. There is no general naming convention, but the developer seems to have one in her mind.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-text-scope-class-key-str","title":"str","text":"

The string in the language defined by the language file.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-text-scope-class-key-desc","title":"desc","text":"

Description of the key. Might be useful to keep the translation accurate at an acceptable margin. Will not be displayed.

"},{"location":"docs/0/0/contribute/translations/#translation-file-structure-text-scope-class-key-tln","title":"tln","text":"

Stands for translators' notes, used by translators to describe to the next translators any compromises done to translate the text to a certain language, or whatnot.

"}]} \ No newline at end of file diff --git a/dev/site/sitemap.xml b/dev/site/sitemap.xml index 24a0d99..354d3e8 100644 --- a/dev/site/sitemap.xml +++ b/dev/site/sitemap.xml @@ -2,177 +2,177 @@ https://m2p.whinyaan.xyz/ - 2023-03-10 - daily - - - https://m2p.whinyaan.xyz/TODO/ - 2023-03-10 + 2023-03-11 daily https://m2p.whinyaan.xyz/changelog/ - 2023-03-10 + 2023-03-11 daily https://m2p.whinyaan.xyz/considerations/ - 2023-03-10 + 2023-03-11 daily https://m2p.whinyaan.xyz/contributing/ - 2023-03-10 + 2023-03-11 daily https://m2p.whinyaan.xyz/diary/ - 2023-03-10 + 2023-03-11 daily https://m2p.whinyaan.xyz/faq/ - 2023-03-10 + 2023-03-11 daily https://m2p.whinyaan.xyz/latest-bump/ - 2023-03-10 + 2023-03-11 daily https://m2p.whinyaan.xyz/latest-commit/ - 2023-03-10 + 2023-03-11 daily https://m2p.whinyaan.xyz/latest-release-notes/ - 2023-03-10 + 2023-03-11 daily https://m2p.whinyaan.xyz/license/ - 2023-03-10 + 2023-03-11 daily https://m2p.whinyaan.xyz/notes-to-self/ - 2023-03-10 + 2023-03-11 daily https://m2p.whinyaan.xyz/terms%20of%20usage/ - 2023-03-10 + 2023-03-11 + daily + + + https://m2p.whinyaan.xyz/todo/ + 2023-03-11 daily https://m2p.whinyaan.xyz/docs/ - 2023-03-10 + 2023-03-11 daily https://m2p.whinyaan.xyz/docs/0/ - 2023-03-10 + 2023-03-11 daily https://m2p.whinyaan.xyz/docs/0/0/ - 2023-03-10 + 2023-03-11 daily https://m2p.whinyaan.xyz/docs/0/0/installation/ - 2023-03-10 + 2023-03-11 daily https://m2p.whinyaan.xyz/docs/0/0/markdown/ - 2023-03-10 + 2023-03-11 daily https://m2p.whinyaan.xyz/docs/0/0/api/ - 2023-03-10 + 2023-03-11 daily https://m2p.whinyaan.xyz/docs/0/0/api/cli/ - 2023-03-10 + 2023-03-11 daily https://m2p.whinyaan.xyz/docs/0/0/api/globals/ - 2023-03-10 + 2023-03-11 daily https://m2p.whinyaan.xyz/docs/0/0/api/info/ - 2023-03-10 + 2023-03-11 daily https://m2p.whinyaan.xyz/docs/0/0/api/md_pp/ - 2023-03-10 + 2023-03-11 daily https://m2p.whinyaan.xyz/docs/0/0/api/pdfgenerator/ - 2023-03-10 + 2023-03-11 daily https://m2p.whinyaan.xyz/docs/0/0/api/utils/ - 2023-03-10 + 2023-03-11 daily https://m2p.whinyaan.xyz/docs/0/0/api/utils/base_cli/ - 2023-03-10 + 2023-03-11 daily https://m2p.whinyaan.xyz/docs/0/0/api/utils/base_exc/ - 2023-03-10 + 2023-03-11 daily https://m2p.whinyaan.xyz/docs/0/0/api/utils/cd/ - 2023-03-10 + 2023-03-11 daily https://m2p.whinyaan.xyz/docs/0/0/api/utils/cfg/ - 2023-03-10 + 2023-03-11 daily https://m2p.whinyaan.xyz/docs/0/0/api/utils/exceptions/ - 2023-03-10 + 2023-03-11 daily https://m2p.whinyaan.xyz/docs/0/0/api/utils/style/ - 2023-03-10 + 2023-03-11 daily https://m2p.whinyaan.xyz/docs/0/0/api/utils/types/ - 2023-03-10 + 2023-03-11 daily https://m2p.whinyaan.xyz/docs/0/0/api/utils/utils/ - 2023-03-10 + 2023-03-11 daily https://m2p.whinyaan.xyz/docs/0/0/contribute/ - 2023-03-10 + 2023-03-11 daily https://m2p.whinyaan.xyz/docs/0/0/contribute/translations/ - 2023-03-10 + 2023-03-11 daily \ No newline at end of file diff --git a/dev/site/sitemap.xml.gz b/dev/site/sitemap.xml.gz index 38139afb28398882dd5248b012d18c281a858830..3ec47eefc0e8e21536b3150582a6b50bb5838a95 100644 GIT binary patch literal 439 zcmV;o0Z9HIiwFquGz??{|8r?{Wo=<_E_iKh0M*zrZ|fis0N}m9BC^!c#z~j<$#J&# z3);CNaCXoGj&hee?yoONswzX5E>C9$+u+mb6JQJIcBkN1?~uu1+*a$RtyT~XS{KJ{ z_453;eyn!=U3bi$fLA3r(zZG?JuHLDbApBR hs`$U__dyvfM9Eo4^8f4L@p2>J{u8e$!3eb$007Vs-O2y} literal 443 zcmV;s0Yv^EiwFpuNeg5G|8r?{Wo=<_E_iKh0M*#NZrd;r0N_1OVF<`5QE`?wkd-CK z>Ls0nGkKDU@Xx$+W%cPx+d<%=OPAopK_aQc;R8hpB)jL6cdOr+$;Pm$9-6jVVbIao zFm9?}Z?E-_>bbw`j@c3NsssnxRD0(1q|`J`4OvDHiJF*4MS5Qvq&_=U+x)EhyHzRY z1lQW7bS~=toP|mnzfR4xw_yed&1wFlI(2@08x6!hntt7`AM5t9erQX`XWvbj-a{C1 z$av@tST}d-rsv8~UylD0y=`B%0$JBQE{+myF_1Nwfy>MynLy5VcjPkF1@erAJPULU za1f|+z(`#0jy}oN>FB*>xxS1Jfv^s-G$k^v#y}`gb{VmnV@>D=fj-9U>3-eDp6ooT}mr5n9@Pf0p5 znPJ3m-iO32-CFh{@@M81xho6B_XT|JH(EUDWoWfoh;ta10WEJHlhkvFe|U*!hs&Vy loNytdD*o^Kbs~ieQF4Yr?z>L-E;mB%{{m{QSIV^(000`Q*rfmf diff --git a/dev/site/terms of usage/index.html b/dev/site/terms of usage/index.html index 45b20bb..8938868 100644 --- a/dev/site/terms of usage/index.html +++ b/dev/site/terms of usage/index.html @@ -1 +1 @@ - Terms of usage - md2pdf

Terms of Usage and Disclaimers

Defined Terms

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.

As used in this Disclaimer, the following terms SHALL have the following meanings (such meanings to be equally applicable to both the singular and plural forms of the terms defined unless explicably mentioned otherwise):

  • Developer hereby means the person who has developed the Project going by the alias of "whi~nyaan!" in the internet, username of "whinee" in "Github", username of "whi_ne#4783" in "Discord" and rightful owner of the electronic mail address "whinyaan@protonmail.com", only meant to be used in singular form

  • Project hereby means the Open Source Project called "md2pdf" developed by the Developer, only meant to be used in singular form

  • Website hereby means a set of interconnected webpages, prepared and maintained as a collection of information for the Project by the Developer, located at m2p.whinyaan.xyz, only meant to be used in singular form; and

  • User hereby means the person who uses this Project and/or Website, regardless of their intentions and attributes including, but not limited to the following:

    age, body size, caste, citizenship, civil status, disability, education, ethnicity, familial status, gender expression, gender identity, genetic information, immigration status, level of experience, nationality, personal appearance, pregnancy, race, religion, sex characteristics, sexual orientation, sexual identity, socio-economic status, tribe, and veteran status

Terms of Usage

As stated in the license agreement, under no circumstance SHALL the Developer of this Project have any liability to the User for any loss or damage of any kind incurred as a result of the use of this Project, even if the Developer or an authorize representative of this Project and/or Website has been notified, orally or written, of the possibility of such damage including, but not limited to the following:

  • Criminal charges due to accessing illegal content where it is banned or prohibited by law; and

  • Damage to device due to usage of the Project and/or Website in said device

Some jurisdiction does not allow limitations on implied warranties or limitations of liability for incidental damages, these limitations MAY not apply to you.

The needy Developer also REQUIRES the Users to pat said developer 3 (three) times a day. Failure to do so MUST revoke the User's rights to use the app.

These Terms of Usage MAY change at any time for any and no reason and it is up to the Users to check for updates from time to time, which means that by no means SHALL the Developer be liable for the User's failure to check the Terms of Usage at a regular basis.

By using the Project and/or the Website, the User agrees and confirms to the license agreement and the Terms of Usage.

Disclaimer

The Developer only intends to use this Project only for educational purposes.

Revisions and Errata

The materials and resources in this Website and the Project MAY include technical, typographical, or photographic errors. The Developer does not promise that any of the materials in this Website and the Project are accurate, complete, or current. The said Developer MAY change the materials contained on its Website at any time without notice. The Developer does not make any commitment to update the materials.

The contents served by the Project is publicly accessible through the Internet. In case of copyright infringement, please direct the complaints, claims, and possible criminal charges against to the respective file hosts and content providers, not to the Project nor to the Developer, as the Developer is not affiliated with them, at any way, shape or form.

The Project is a program that serves contents like a normal browser do through scraping 3rd-party websites that are publicly accessible via any regular web browser, however it does less requests than a normal browser would, and is sophisticated enough to serve the content how the Developer would want to. It is the responsibility of the Users to avoid any actions that might violate the laws governing their locality.

The Developer

The Project is created in good faith that this will only serve an educational purpose for the Developer and the Users and will only be used for that said purpose.

By no means harassing the Developer including, but not limited to the following, is legal nor ethically and morally correct:

  • Exploiting the undisclosed personal information of the Developer against them, possibly accessed through illegal means, including, but not limited to the following:

    • Physical/Online Stalking

    • Hacking; and

    • Social Engineering

  • Sending threatening messages, mentioning doing physical harm to the Developer or not, attempts to morally degrade the said Developer, including, but not limited to the following ways:

    • Through social media platforms, including but not limited to Discord, Youtube, and Facebook

    • Through e-mail; and

    • Through physical mail

The Developer will act legally against those who have done anything illegal against the said Developer, including, but not limited to the following above.

For any concerns regarding the legality of the Project and/or Websites, begin by creating a new issue or through emailing me at whinyaan@protonmail.com or contacting me in Discord at whi_ne#4783.

\ No newline at end of file + Terms of usage - md2pdf

Terms of Usage and Disclaimers

Defined Terms

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.

As used in this Disclaimer, the following terms SHALL have the following meanings (such meanings to be equally applicable to both the singular and plural forms of the terms defined unless explicably mentioned otherwise):

  • Developer hereby means the person who has developed the Project going by the alias of "whi~nyaan!" in the internet, username of "whinee" in "Github", username of "whi_ne#4783" in "Discord" and rightful owner of the electronic mail address "whinyaan@protonmail.com", only meant to be used in singular form

  • Project hereby means the Open Source Project called "md2pdf" developed by the Developer, only meant to be used in singular form

  • Website hereby means a set of interconnected webpages, prepared and maintained as a collection of information for the Project by the Developer, located at m2p.whinyaan.xyz, only meant to be used in singular form; and

  • User hereby means the person who uses this Project and/or Website, regardless of their intentions and attributes including, but not limited to the following:

    age, body size, caste, citizenship, civil status, disability, education, ethnicity, familial status, gender expression, gender identity, genetic information, immigration status, level of experience, nationality, personal appearance, pregnancy, race, religion, sex characteristics, sexual orientation, sexual identity, socio-economic status, tribe, and veteran status

Terms of Usage

As stated in the license agreement, under no circumstance SHALL the Developer of this Project have any liability to the User for any loss or damage of any kind incurred as a result of the use of this Project, even if the Developer or an authorize representative of this Project and/or Website has been notified, orally or written, of the possibility of such damage including, but not limited to the following:

  • Criminal charges due to accessing illegal content where it is banned or prohibited by law; and

  • Damage to device due to usage of the Project and/or Website in said device

Some jurisdiction does not allow limitations on implied warranties or limitations of liability for incidental damages, these limitations MAY not apply to you.

The needy Developer also REQUIRES the Users to pat said developer 3 (three) times a day. Failure to do so MUST revoke the User's rights to use the app.

These Terms of Usage MAY change at any time for any and no reason and it is up to the Users to check for updates from time to time, which means that by no means SHALL the Developer be liable for the User's failure to check the Terms of Usage at a regular basis.

By using the Project and/or the Website, the User agrees and confirms to the license agreement and the Terms of Usage.

Disclaimer

The Developer only intends to use this Project only for educational purposes.

Revisions and Errata

The materials and resources in this Website and the Project MAY include technical, typographical, or photographic errors. The Developer does not promise that any of the materials in this Website and the Project are accurate, complete, or current. The said Developer MAY change the materials contained on its Website at any time without notice. The Developer does not make any commitment to update the materials.

The contents served by the Project is publicly accessible through the Internet. In case of copyright infringement, please direct the complaints, claims, and possible criminal charges against to the respective file hosts and content providers, not to the Project nor to the Developer, as the Developer is not affiliated with them, at any way, shape or form.

The Project is a program that serves contents like a normal browser do through scraping 3rd-party websites that are publicly accessible via any regular web browser, however it does less requests than a normal browser would, and is sophisticated enough to serve the content how the Developer would want to. It is the responsibility of the Users to avoid any actions that might violate the laws governing their locality.

The Developer

The Project is created in good faith that this will only serve an educational purpose for the Developer and the Users and will only be used for that said purpose.

By no means harassing the Developer including, but not limited to the following, is legal nor ethically and morally correct:

  • Exploiting the undisclosed personal information of the Developer against them, possibly accessed through illegal means, including, but not limited to the following:

    • Physical/Online Stalking

    • Hacking; and

    • Social Engineering

  • Sending threatening messages, mentioning doing physical harm to the Developer or not, attempts to morally degrade the said Developer, including, but not limited to the following ways:

    • Through social media platforms, including but not limited to Discord, Youtube, and Facebook

    • Through e-mail; and

    • Through physical mail

The Developer will act legally against those who have done anything illegal against the said Developer, including, but not limited to the following above.

For any concerns regarding the legality of the Project and/or Websites, begin by creating a new issue or through emailing me at whinyaan@protonmail.com or contacting me in Discord at whi_ne#4783.

\ No newline at end of file diff --git a/dev/site/todo/index.html b/dev/site/todo/index.html new file mode 100644 index 0000000..517a563 --- /dev/null +++ b/dev/site/todo/index.html @@ -0,0 +1 @@ + TODO - md2pdf

TODO

Legend

Tags

  • feat: Feature

Todo

  • [ ] [docs]
  • [ ] [feat] n-column support
  • [ ] [feat] GUI
  • [ ] [feat] Custom Help Function (to only compute help page's width when help is actually called; the CLI is actually already fast enough that this might not be necessary, but is just a mere novelty)

In Progress

  • [ ] Custom mermaid.js renderer (will be done after the GUI, as the HUI will be written in JS, and the rendered will be using JS too)

Done

\ No newline at end of file diff --git a/docs/TODO.md b/docs/TODO.md deleted file mode 100644 index 3765b59..0000000 --- a/docs/TODO.md +++ /dev/null @@ -1,19 +0,0 @@ -# TODO - - - - -

Todo

- -- [ ] n-column support -- [ ] GUI -- [ ] Custom Help Function (to only compute help page's width when help is actually called; the CLI is actually already fast enough that this might not be necessary, but is just a mere novelty) - -

In Progress

- -- [ ] Custom mermaid.js renderer (will be done after the GUI, as the HUI will be written in JS, and the rendered will be using JS too) - -

Done

- -- [x] Custom KaTex renderer (as the best one for Weasyprint use, [mbarkhau/markdown-katex](https://github.com/mbarkhau/markdown-katex) is so dang slow) \ No newline at end of file diff --git a/docs/docs/0/0/api/cli.md b/docs/docs/0/0/api/cli.md index e785c64..fcc9fd0 100644 --- a/docs/docs/0/0/api/cli.md +++ b/docs/docs/0/0/api/cli.md @@ -49,10 +49,12 @@ Return first argument that is not `None` and convert it into HTML.

Args:

+---- - raw_MD (`str`): Raw Markdown string. - MD_path (`str`): Path to Markdown file.

Returns:

+------- `string`: Raw HTML string. \ No newline at end of file diff --git a/docs/docs/0/0/api/utils/base_cli.md b/docs/docs/0/0/api/utils/base_cli.md index 3eae227..0b8ec53 100644 --- a/docs/docs/0/0/api/utils/base_cli.md +++ b/docs/docs/0/0/api/utils/base_cli.md @@ -1,6 +1,19 @@ # **[src](../index.md).[utils](../utils.md).[base_cli](base_cli.md)** +Hereunder resides functions for constructing CLI for this program. + +> This module heavily documents my descent to madness. +> +> An unholy amalgamation of megalamonia, depression, God complex, and impostor syndrome filled my broken heart. +> +> This file is the digital manifestation of my mental woes. +> +> Masochistic tendencies fuelling my coding sessions. +> +> I wish upon this abyss to not touch this file ever again. + +whi~nyaan! ― 2023

Functions

@@ -255,6 +268,8 @@ To customize the command class used, set the Returns wrappers for a click command evaluated from the given arguments. +Initialize object. +

Args:

@@ -330,6 +345,7 @@ The command wrapper. The options wrapper. + My God in heaven, I'm agnostic, but please save me from all evil. Amen. @@ -347,6 +363,7 @@ My God in heaven, I'm agnostic, but please save me from all evil. Amen. ``` +Wrap given function with corresponding click decorators.

Args:

diff --git a/docs/docs/0/0/api/utils/cd.md b/docs/docs/0/0/api/utils/cd.md index aafeb93..4a91bfe 100644 --- a/docs/docs/0/0/api/utils/cd.md +++ b/docs/docs/0/0/api/utils/cd.md @@ -85,7 +85,7 @@ Custom dictionary. ``` -_summary_ +_summary_. Return States | State \|| Return Type \|| Description | diff --git a/docs/docs/0/0/api/utils/exceptions.md b/docs/docs/0/0/api/utils/exceptions.md index d40c040..6e3cdcd 100644 --- a/docs/docs/0/0/api/utils/exceptions.md +++ b/docs/docs/0/0/api/utils/exceptions.md @@ -1,6 +1,7 @@ # **[src](../index.md).[utils](../utils.md).[exceptions](exceptions.md)** +`Common` exceptions are raised if an error occured and it is of the `Common` exception's common variant of error.

Classes

diff --git a/docs/docs/0/0/api/utils/utils.md b/docs/docs/0/0/api/utils/utils.md index 7761bbd..1f1e9f6 100644 --- a/docs/docs/0/0/api/utils/utils.md +++ b/docs/docs/0/0/api/utils/utils.md @@ -158,7 +158,7 @@ Fill given list (`ls`) with `filler` up to `length`. ``` -"If Not `os.path.isdir`, Make Directories" +"If Not `os.path.isdir`, Make Directories".

Args:

@@ -215,7 +215,7 @@ If Var is None, return Default else var. ``` -Literal Evaluation +Literal Evaluation.

Args:

@@ -237,7 +237,7 @@ Literal Evaluation ``` -No operation +No operation. @@ -283,7 +283,7 @@ Iterate through the dictionary, find the values in the given string and replace ``` -Return First Non-None +Return First Non-None. Return the first argument that is not `None`, else return `None`. @@ -443,19 +443,31 @@ If given string is decimal, convert string to integer, else return False.

which_ls

```python -(cmd: str, mode: Optional[int] = None, path: str | None = None) ‑> Union[tuple[str], tuple[str, ...], ForwardRef(None)] +(cmd: str, mode: Optional[int] = 1, path: str | None = '/home/whine/whi_ne/3/projects/personal/tools/md2pdf-rewrite/pyenv/bin:/home/whine/bin:/home/whine/whi_ne/2/.local:/home/whine/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl:/var/lib/snapd/snap/bin') ‑> Union[tuple[str], tuple[str, ...], ForwardRef(None)] ``` -Yoinked from shutil. Given a command, mode, and a PATH string, return the path which -conforms to the given mode on the PATH, or None if there is no such -file. +Given a command, mode, and a PATH string, return the path which conforms to the given mode on the PATH, or None if there is no such file. -`mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result +Notes: +- Yoinked from shutil. +- `mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result of os.environ.get("PATH"), or can be overridden with a custom search path. +

Args:

+ +- cmd (`str`): Executable to look for. +- mode (`Optional[int]`, optional): Executable permissions to look for. Defaults to `os.F_OK | os.X_OK`. +- path (`Optional[str]`, optional): The PATH to where the executable can be found. Defaults to `os.environ.get("PATH", None)`. + + +

Returns:

+ +`Optional[types.TupleStr]`: List of path where executable is found at. + +

Classes

diff --git a/docs/todo.md b/docs/todo.md new file mode 100644 index 0000000..f77212a --- /dev/null +++ b/docs/todo.md @@ -0,0 +1,26 @@ +# TODO + + + + +

Legend

+ +

Tags

+ +- **feat**: Feature + +

Todo

+ +- [ ] [docs] +- [ ] [feat] n-column support +- [ ] [feat] GUI +- [ ] [feat] Custom Help Function (to only compute help page's width when help is actually called; the CLI is actually already fast enough that this might not be necessary, but is just a mere novelty) + +

In Progress

+ +- [ ] Custom mermaid.js renderer (will be done after the GUI, as the HUI will be written in JS, and the rendered will be using JS too) + +

Done

+ +- [x] Custom KaTex renderer (as the best one for Weasyprint use, [mbarkhau/markdown-katex](https://github.com/mbarkhau/markdown-katex) is so dang slow) \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 9352f02..1ea2718 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,62 @@ -[tool.bandit] -targets = ["src"] -skips = ["B101", "B404", "B603"] \ No newline at end of file +[tool.ruff] +# Enable pycodestyle (`E`) and Pyflakes (`F`) codes by default. +select = ["C90", "D", "E", "F", "N", "RUF"] +# select = ["D"] +ignore = [ + "D100", + "D101", + "D102", + "D103", + "D104", + "D105", + "D106", + "D107", + "D202", + "D203", + "D212", + "D401", + "D406", + "D407", + "D417", + "E501" +] + +# Allow autofix for all enabled rules (when `--fix`) is provided. +fixable = ["D"] +# fixable = [] +unfixable = [] + +# Exclude a variety of commonly ignored directories. +exclude = [ + ".bzr", + ".direnv", + ".eggs", + ".git", + ".hg", + ".mypy_cache", + ".nox", + ".pants.d", + ".pytype", + ".ruff_cache", + ".svn", + ".tox", + ".venv", + "__pypackages__", + "_build", + "buck-out", + "build", + "dist", + "node_modules", + "pyenv", + "venv", +] + +line-length = 88 + +target-version = "py310" + +[tool.ruff.mccabe] +max-complexity = 3 + +[tool.ruff.pycodestyle] +ignore-overlong-task-comments = false \ No newline at end of file diff --git a/src/cli.py b/src/cli.py index f8fe70c..3e722ee 100755 --- a/src/cli.py +++ b/src/cli.py @@ -48,15 +48,18 @@ def cli(**kwargs: dict[str, Any]) -> None: def mc(raw_MD: str, MD_path: str, hf: bool | None = None) -> str | None: - """Markdown chooser. + """ + Markdown chooser. Return first argument that is not `None` and convert it into HTML. Args: + ---- - raw_MD (`str`): Raw Markdown string. - MD_path (`str`): Path to Markdown file. Returns: + ------- `string`: Raw HTML string. """ @@ -73,7 +76,8 @@ def mc(raw_MD: str, MD_path: str, hf: bool | None = None) -> str | None: def hmc( raw_HTML: str, HTML_path: str, raw_MD: str, MD_path: str, hf: bool | None = None ) -> str: - """HTML or Markdown chooser. + """ + HTML or Markdown chooser. Return first argument that is not `None` and convert it into HTML, if it is not already. @@ -134,11 +138,13 @@ def convert( # type: ignore[no-untyped-def] orientation, margin, ) -> None: - """Converts input markdown to styled HTML and renders it to a PDF file. + """ + Converts input markdown to styled HTML and renders it to a PDF file. Arguments are explained in the CLI help page. - Notes: + Notes + ----- - The following is the precedence order of header and footer application (`>` means "precedes"): - For header: `header_raw` > `header_path` > `md_header_raw` > `md_header_path` diff --git a/src/info.py b/src/info.py index c2d450b..a39b7af 100644 --- a/src/info.py +++ b/src/info.py @@ -76,7 +76,7 @@ TW = get_terminal_size().columns """Stands for terminal width. """ -except OSError as e: +except OSError: TW = 0 MACHINE = platform.machine() diff --git a/src/md_pp.py b/src/md_pp.py index 343ee6f..68feecf 100644 --- a/src/md_pp.py +++ b/src/md_pp.py @@ -93,7 +93,7 @@ def _get_bin_cmd() -> str: try: npx_cmd = NPX_KATEX_FMT.format(i) output_data = subprocess.check_output( - npx_cmd.split() + ["--version"], stderr=subprocess.STDOUT + [*npx_cmd.split(), "--version"], stderr=subprocess.STDOUT ) output_text = output_data.decode("utf-8") if SEMVER_RE.match(output_text.strip()) is None: @@ -112,7 +112,7 @@ def get_bin_cmd() -> list[str]: bin_cmd: list[str] = bin.split() if "npx" in bin: output_data = subprocess.check_output( - bin_cmd + ["--version"], stderr=subprocess.STDOUT + [*bin_cmd, "--version"], stderr=subprocess.STDOUT ) if SEMVER_RE.match(output_data.decode("utf-8").strip()) is not None: return bin_cmd @@ -166,7 +166,7 @@ def katex2html(marker: str, tex: str) -> tuple[str, str]: # type: ignore[return err_msg = f"Error processing '{tex}': {output}" raise Exception(err_msg) return marker, htmlsvg2img(stdout) - except Exception as e: # nosec B110 + except Exception: # nosec B110 pass diff --git a/src/pdfgenerator.py b/src/pdfgenerator.py index 4933854..5fadf64 100644 --- a/src/pdfgenerator.py +++ b/src/pdfgenerator.py @@ -123,7 +123,8 @@ def __init__( size: str, margin: list[str], ): - """Initialize PDF Generator. + """ + Initialize PDF Generator. Notes: - The `size` and `margin` arguments are applied to the PDF like CSS does. See https://developer.mozilla.org/en-US/docs/Web/CSS/@page/size and https://developer.mozilla.org/en-US/docs/Web/CSS/margin#syntax respectively for more details. @@ -166,7 +167,8 @@ def __init__( def _compute_element( self, element: str, element_string: str, page: int, pages: int ): - """Compute element in HTML. + """ + Compute element in HTML. Args: - element (`str`): Element's name. @@ -194,7 +196,8 @@ def _compute_element( def _compute_overlay_element( self, element: str, element_string: Optional[str] ) -> int: - """Compute overlay element. + """ + Compute overlay element. Set self.`element`_body, self.`element`_height to element's content and height, else if element is not found, set to `None`, `0` respectively. @@ -231,7 +234,8 @@ def _apply_overlay_on_main(self, main_doc): # type: ignore[no-untyped-def] ).all_children() def render_pdf(self) -> bytes: - """Return the rendered PDF. + """ + Return the rendered PDF. Returns: `bytes`: The rendered PDF. diff --git a/src/utils/base_cli.py b/src/utils/base_cli.py index aa89554..e797f69 100644 --- a/src/utils/base_cli.py +++ b/src/utils/base_cli.py @@ -1,4 +1,19 @@ -from __future__ import unicode_literals +""" +Hereunder resides functions for constructing CLI for this program. + +> This module heavily documents my descent to madness. +> +> An unholy amalgamation of megalamonia, depression, God complex, and impostor syndrome filled my broken heart. +> +> This file is the digital manifestation of my mental woes. +> +> Masochistic tendencies fuelling my coding sessions. +> +> I wish upon this abyss to not touch this file ever again. + +whi~nyaan! ― 2023 + +""" import os import typing @@ -41,22 +56,6 @@ warnings.filterwarnings("ignore") -""" - -This module heavily documents my descent to madness. - -An unholy amalgamation of megalamonia, depression, God complex, and impostor syndrome filled my broken heart. - -This file is the digital manifestation of my mental woes. - -Masochistic tendencies fuelling my coding sessions. - -I wish upon this abyss to not touch this file ever again. - - whi~nyaan! ― 2023 - -""" - # Constants CLICK_CMD_OPTIONS_EXAMPLE_INDICATOR: Final[str] = "Ex.: " DEFAULT_CLI_KWARGS: Final[dict[str, Any]] = {"metavar": ""} @@ -222,6 +221,8 @@ class cao: def __init__(self, group: Group) -> None: """ + Initialize object. + Args: - group (`Group`): Command group of the command to be under. @@ -231,7 +232,8 @@ def __init__(self, group: Group) -> None: self.group: Group = group def command(self) -> Callable[[Callable[..., Any]], Callable[..., Any]]: - """The command wrapper. + """ + The command wrapper. Returns: `Callable[[Callable[..., Any]], Callable[..., Any]]` @@ -279,7 +281,8 @@ def inner( return inner def arguments(self) -> Callable[[Callable[..., Any]], Callable[..., Any]]: - """The arguments wrapper. + """ + The arguments wrapper. Returns: `Callable[[Callable[..., Any]], Callable[..., Any]]` @@ -305,7 +308,9 @@ def inner( return inner def options(self) -> Callable[[Callable[..., Any]], Callable[..., Any]]: - """The options wrapper. + """ + The options wrapper. + My God in heaven, I'm agnostic, but please save me from all evil. Amen. Returns: @@ -489,6 +494,8 @@ def inner(**kwargs: dict[str, Any]) -> Any: def wrap(self, func: Callable[..., Any]) -> Callable[..., Any]: """ + Wrap given function with corresponding click decorators. + Args: - func (`Callable[..., Any]`): Function to be wrapped. @@ -508,7 +515,8 @@ def wrap(self, func: Callable[..., Any]) -> Callable[..., Any]: def command( group: Group, ) -> Callable[[Callable[..., Any]], Callable[..., Any]]: - """Wrapper for click commands. + """ + Wrapper for click commands. Args: - group (`Group`): Command group of the command to be under. @@ -704,7 +712,8 @@ def init(idx: int) -> None: def de_rcfg() -> CustomDict: - """Return parsed configuration file, fetched from the CFLOP. + """ + Return parsed configuration file, fetched from the CFLOP. Returns: `dict[Any, Any]`: _description_ @@ -713,7 +722,8 @@ def de_rcfg() -> CustomDict: def de_wcfg(value: dict[Any, Any] | list[Any]) -> None: - """Write given value to the configuration file, fetched from the CFLOP. + """ + Write given value to the configuration file, fetched from the CFLOP. Args: - value (`dict[Any, Any] | list[Any]`): dictionary to overwrite the configuration file, fetched from the CFLOP. diff --git a/src/utils/base_exc.py b/src/utils/base_exc.py index 5025066..48fd83b 100644 --- a/src/utils/base_exc.py +++ b/src/utils/base_exc.py @@ -9,7 +9,8 @@ def c_exc_str(cls: Type[BaseException]) -> Type[BaseException]: - """Decorator to add the __str__ method to an exception. + """ + Decorator to add the __str__ method to an exception. Args: - cls (`BaseException`): The exception to add the __str__ method to. @@ -20,28 +21,27 @@ def c_exc_str(cls: Type[BaseException]) -> Type[BaseException]: old_init: Callable[..., None] = cls.__init__ - def __init__( - self: BaseException, *args: types.Args, **kwargs: types.Kwargs - ) -> None: + def init(self: BaseException, *args: types.Args, **kwargs: types.Kwargs) -> None: old_init(self, *args, **kwargs) pp(S.p_critical(S.t_critical(self.message))) if details := getattr(self, "details", None): print(details) - def __str__(self: BaseException) -> str: + def str_fn(self: BaseException) -> str: msg: str = self.message # details: str=getattr(self, 'details') # if details: # return msg + '\n' + details return msg - cls.__init__ = __init__ # type: ignore[assignment] - cls.__str__ = __str__ # type: ignore[assignment] + cls.__init__ = init # type: ignore[assignment] + cls.__str__ = str_fn # type: ignore[assignment] return cls def c_exc(cls: Type[BaseException]) -> Type[BaseException]: - """Decorator to raise a custom exception. + """ + Decorator to raise a custom exception. This function gives the class an __init__ function that raises the exception. If the class does not inherit from any Exception, it will be automatically inherit from Exception. diff --git a/src/utils/cd.py b/src/utils/cd.py index d0a2109..6670d49 100644 --- a/src/utils/cd.py +++ b/src/utils/cd.py @@ -51,7 +51,8 @@ def traverse( idx: int = 0, og_path: Optional[str] = None, ) -> tuple[int, Any | dict[str, int]] | Any: - """_summary_ + """ + _summary_. Return States | State \|| Return Type \|| Description | diff --git a/src/utils/cfg.py b/src/utils/cfg.py index 21d7423..fb50e9b 100644 --- a/src/utils/cfg.py +++ b/src/utils/cfg.py @@ -38,7 +38,8 @@ def __init__(self, ext: str) -> None: def pcfg(d: str, type: str) -> CustomDict: - """Parse the given string as the given type. + """ + Parse the given string as the given type. Args: - d (`str`): String to parse. @@ -55,7 +56,8 @@ def pcfg(d: str, type: str) -> CustomDict: def dcfg(value: dict[str, Any], ext: str) -> str: - """Dump the given value to a string with the given extension. + """ + Dump the given value to a string with the given extension. Args: - value (`dict`): Value to dump to a string. @@ -72,7 +74,8 @@ def dcfg(value: dict[str, Any], ext: str) -> str: def rcfg(file: str) -> CustomDict: - """Read the contents of a file with the given file name. + """ + Read the contents of a file with the given file name. Args: - file (`str`): File name of the file to read the contents of. @@ -90,7 +93,8 @@ def rcfg(file: str) -> CustomDict: def wcfg(file: str, value: dict[Any, Any] | list[Any]) -> None: - """Write the given value to a file with the given file name. + """ + Write the given value to a file with the given file name. Args: - file (`str`): File name of the file to write the value to. diff --git a/src/utils/exceptions.py b/src/utils/exceptions.py index 2828089..8aa94af 100644 --- a/src/utils/exceptions.py +++ b/src/utils/exceptions.py @@ -1,3 +1,5 @@ +"""`Common` exceptions are raised if an error occured and it is of the `Common` exception's common variant of error.""" + from typing import Any, Optional try: @@ -10,17 +12,14 @@ from src.info import PLATFORM, PSH, TW from src.utils.base_exc import c_exc, c_exc_str -""" -`Common` exceptions are raised if an error occured and it is of the `Common` exception's common variant of error. -""" - class GeneralExceptions: class ValidationError: @c_exc_str class FileNotFound(FileNotFoundError): def __init__(self, fp: str) -> None: - """Raised when a file in a given path is not found. + """ + Raised when a file in a given path is not found. Args: - parameter (`fp`): Path of the file that can not be found. @@ -32,7 +31,8 @@ class Arguments: def __init__( self, parameter: str, argument: Any, specification: str ) -> None: - """Raised when a parameter is required to be of specification, but is not followed. + """ + Raised when a parameter is required to be of specification, but is not followed. Args: - parameter (`str`): Name of the parameter. @@ -50,7 +50,8 @@ class PrerequisiteNotFound: def __init__( self, prerequisite: str, inst_instruction: Optional[str] = None ) -> None: - """Raised when a prerequisite is needed by the program, but is not installed in the machine. + """ + Raised when a prerequisite is needed by the program, but is not installed in the machine. Args: - prerequisite (`str`): Name of the prerequisite. @@ -63,7 +64,8 @@ class CLIExceptions: @c_exc_str class TerminalTooThin(Exception): def __init__(self, min_width: int) -> None: - """Raised when terminal is too thin for content to be rendered. + """ + Raised when terminal is too thin for content to be rendered. Args: - min_width (`int`): Required minimum terminal width. @@ -74,7 +76,8 @@ class ValidationError: @c_exc_str class OptionRequired(Exception): def __init__(self, option: str) -> None: - """Raised when an option is required but no argument is passed. + """ + Raised when an option is required but no argument is passed. Args: - option (`str`): Required option with no arguments passed into it. @@ -117,7 +120,8 @@ def __init__( class Internals: class StateUnexpected(IndexError): def __init__(self, state: Any, max_state: int) -> None: - """Raised when the state passed in between functions is not of type `int` or exceeds the bounds of possible states. + """ + Raised when the state passed in between functions is not of type `int` or exceeds the bounds of possible states. Args: - state (`Any`): Faulty state. diff --git a/src/utils/style.py b/src/utils/style.py index 24ff4f3..ac9b681 100755 --- a/src/utils/style.py +++ b/src/utils/style.py @@ -158,7 +158,8 @@ class C: def pp( t: Any, ca: Optional[bool] = None, *args: list[Any], **kwargs: dict[str, Any] ) -> None: - """Center rich printable objects, then pretty print it. + """ + Center rich printable objects, then pretty print it. Args: - t (`Any`): Rich printable object to be centered, then pretty printed. @@ -174,7 +175,8 @@ def pp( class ct: @staticmethod def group(*ls: ConsoleRenderable | RichCast | str) -> Group: - """Group given list of rich printable objects. + """ + Group given list of rich printable objects. Returns: `Group`: Group of rich printable objects @@ -186,7 +188,8 @@ def group(*ls: ConsoleRenderable | RichCast | str) -> Group: @staticmethod def table(cols: list[str], rows: list[list[str]]) -> None: - """Print table from given list of str and list of list of strings for the columns and rows respectively. + """ + Print table from given list of str and list of list of strings for the columns and rows respectively. Args: - cols (`list[str]`): List of string for column labels. diff --git a/src/utils/utils.py b/src/utils/utils.py index f54d6ab..2b146cc 100644 --- a/src/utils/utils.py +++ b/src/utils/utils.py @@ -175,7 +175,8 @@ class ExtQuestion(Question): # type: ignore[misc] kbi = DEFAULT_KBI_MESSAGE def ask(self, patch_stdout: Optional[bool] = None, **kwargs: dict[str, Any]) -> tuple[bool, Any]: # type: ignore[override] - """Ask the question synchronously and return user response. + """ + Ask the question synchronously and return user response. Args: - patch_stdout (`bool`, optional): Ensure that the prompt renders correctly if other threads are printing to stdout. Defaults to `None`. @@ -220,7 +221,8 @@ def dpop( pop: list[int | list[str | int | tuple[str, ...]] | str], de: Optional[Any] = None, ) -> Any: - """Iterate through the preferred order of precedence (`pop`) and see if the value exists in the dictionary. If it does, return it. If not, return `de`. + """ + Iterate through the preferred order of precedence (`pop`) and see if the value exists in the dictionary. If it does, return it. If not, return `de`. Args: - d (`Dict[Any, Any]`): Dictionary to retrieve the value from. @@ -238,7 +240,8 @@ def dpop( def dt(dt: str, format: str) -> str: - """Remove timezone from datetime and format it to ISO 8601 format. + """ + Remove timezone from datetime and format it to ISO 8601 format. Args: - dt (`str`): Unformatted datetime string to be formatted to ISO 8601 format @@ -264,7 +267,8 @@ def dt(dt: str, format: str) -> str: def dt_ts(ts: str) -> str: - """Convert the given unix timestamp to ISO 8601 format. + """ + Convert the given unix timestamp to ISO 8601 format. Args: - ts (`str`): unix timestamp to be converted to ISO 8601 format @@ -277,7 +281,8 @@ def dt_ts(ts: str) -> str: def file_exists(fp: str) -> str: - """Check if the given file path exists. + """ + Check if the given file path exists. Args: - fp (`str`): File path to check if it exists. @@ -296,7 +301,8 @@ def file_exists(fp: str) -> str: def fill_ls( *, ls: types.SequenceAny, length: int, filler: Optional[Any] = None ) -> types.SequenceAny: - """Fill given list (`ls`) with `filler` up to `length`. + """ + Fill given list (`ls`) with `filler` up to `length`. Args: - ls (`types.SequenceAny`): List to fill with `filler` up to `length` @@ -314,7 +320,8 @@ def fill_ls( def inmd(p: str, ls: Optional[list[str]] = None) -> str: - """ "If Not `os.path.isdir`, Make Directories" + """ + "If Not `os.path.isdir`, Make Directories". Args: - p (`str`): The path to be created, if it does not exist. @@ -340,7 +347,8 @@ def iter_ls_with_items( def ivnd(var: Any, de: Any) -> Any: - """If Var is None, return Default else var. + """ + If Var is None, return Default else var. Args: - var (`Any`): Variable to check if it is None. @@ -355,7 +363,8 @@ def ivnd(var: Any, de: Any) -> Any: def le(expr: str) -> Any: - """Literal Evaluation + """ + Literal Evaluation. Args: - expr (`str`): Expression to be evaluated. @@ -368,7 +377,7 @@ def le(expr: str) -> Any: def noop(*args: types.ListAny, **kwargs: dict[str, Any]) -> None: - """No operation""" + """No operation.""" pass @@ -377,7 +386,8 @@ def noop_single_kwargs(arg: Any) -> Any: def repl(s: str, repl_dict: dict[str, list[str]]) -> str: - """Iterate through the dictionary, find the values in the given string and replace it with the corresponding key, and output the modified string. + """ + Iterate through the dictionary, find the values in the given string and replace it with the corresponding key, and output the modified string. Args: - s (`str`): String to modify. @@ -394,7 +404,8 @@ def repl(s: str, repl_dict: dict[str, list[str]]) -> str: def rfnn(*args: types.ListAny) -> Any: - """Return First Non-None + """ + Return First Non-None. Return the first argument that is not `None`, else return `None`. @@ -419,7 +430,8 @@ def run_mp_star(func: types.CallableAny, iterable: types.IterIterAny) -> types.L def run_mp_qir( func: types.CallableAny, iterable: types.IterAny, callback: types.CallableAny ) -> None: - """Run `multiprocessing.Pool().map_async()`, and quit in return. + """ + Run `multiprocessing.Pool().map_async()`, and quit in return. Iterate over `iterable` and apply iterated item to `func` asynchronously. Wait for a single process in the pool to return, and terminate the pool. @@ -439,7 +451,8 @@ def run_mp_qir( def run_mp_star_qir( func: types.CallableAny, iterable: types.IterIterAny, callback: types.CallableAny ) -> None: - """Run `multiprocessing.Pool().starmap_async()`, and quit in return. + """ + Run `multiprocessing.Pool().starmap_async()`, and quit in return. Iterate over `iterable` and apply iterated items to `func` asynchronously. Wait for a single process in the pool to return, and terminate the pool. """ @@ -467,7 +480,8 @@ def run_mp_star_qgr( def sanitize_text(s: str) -> str: - """Sanitize input text. + """ + Sanitize input text. Reference: https://stackoverflow.com/a/93029 @@ -481,7 +495,8 @@ def sanitize_text(s: str) -> str: def str2int(s: str) -> Optional[int]: - """If given string is decimal, convert string to integer, else return False. + """ + If given string is decimal, convert string to integer, else return False. Args: s (str): string to convert to integer. @@ -533,20 +548,27 @@ def squery( def which_ls( - cmd: str, mode: Optional[int] = None, path: Optional[str] = None + cmd: str, + mode: Optional[int] = os.F_OK | os.X_OK, + path: Optional[str] = os.environ.get("PATH", None), ) -> Optional[types.TupleStr]: """ - Yoinked from shutil. Given a command, mode, and a PATH string, return the path which - conforms to the given mode on the PATH, or None if there is no such - file. + Given a command, mode, and a PATH string, return the path which conforms to the given mode on the PATH, or None if there is no such file. - `mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result + Notes: + - Yoinked from shutil. + - `mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result of os.environ.get("PATH"), or can be overridden with a custom search path. + Args: + - cmd (`str`): Executable to look for. + - mode (`Optional[int]`, optional): Executable permissions to look for. Defaults to `os.F_OK | os.X_OK`. + - path (`Optional[str]`, optional): The PATH to where the executable can be found. Defaults to `os.environ.get("PATH", None)`. + + Returns: + `Optional[types.TupleStr]`: List of path where executable is found at. """ - if mode is None: - mode = os.F_OK | os.X_OK # If we're given a path with a directory part, look it up directly rather # than referring to PATH directories. This includes checking relative to the @@ -557,15 +579,11 @@ def which_ls( return None if path is None: - path = os.environ.get("PATH", None) - if path is None: - try: - path = os.confstr("CS_PATH") - except (AttributeError, ValueError): - # os.confstr() or CS_PATH is not available - path = os.defpath - # bpo-35755: Don't use os.defpath if the PATH environment variable is - # set to an empty string + try: + path = os.confstr("CS_PATH") + except (AttributeError, ValueError): + # os.confstr() or CS_PATH is not available + path = os.defpath # PATH='' doesn't match, whereas PATH=':' looks in the current directory if not path: @@ -599,7 +617,7 @@ def which_ls( op = set() for dir in path: normdir = os.path.normcase(dir) - if not normdir in seen: + if normdir not in seen: seen.add(normdir) for thefile in files: name = os.path.join(dir, thefile)