From db0746c16ebc2cae9499011abb79e8f918f2ac54 Mon Sep 17 00:00:00 2001 From: Antoine Pietri Date: Sun, 24 May 2020 11:42:28 +0200 Subject: [PATCH] Add documentation for OCaml --- .../templates/pages/about_tmpl.coffee | 5 + assets/javascripts/vendor/prism.js | 5698 +++++++++-------- docs/file-scrapers.md | 12 + lib/docs/filters/ocaml/clean_html.rb | 13 + lib/docs/filters/ocaml/entries.rb | 65 + lib/docs/scrapers/ocaml.rb | 28 + public/icons/docs/ocaml/16.png | Bin 0 -> 606 bytes public/icons/docs/ocaml/16@2x.png | Bin 0 -> 1183 bytes public/icons/docs/ocaml/SOURCE | 2 + 9 files changed, 3132 insertions(+), 2691 deletions(-) create mode 100644 lib/docs/filters/ocaml/clean_html.rb create mode 100644 lib/docs/filters/ocaml/entries.rb create mode 100644 lib/docs/scrapers/ocaml.rb create mode 100644 public/icons/docs/ocaml/16.png create mode 100644 public/icons/docs/ocaml/16@2x.png create mode 100644 public/icons/docs/ocaml/SOURCE diff --git a/assets/javascripts/templates/pages/about_tmpl.coffee b/assets/javascripts/templates/pages/about_tmpl.coffee index 8ac93ed4..1b8082dc 100644 --- a/assets/javascripts/templates/pages/about_tmpl.coffee +++ b/assets/javascripts/templates/pages/about_tmpl.coffee @@ -541,6 +541,11 @@ credits = [ '2005-2019 NumPy Developers', 'BSD', 'https://raw.githubusercontent.com/numpy/numpy/master/LICENSE.txt' + ], [ + 'OCaml', + '1995-2020 Inria', + 'CC BY-SA', + 'https://ocaml.org/docs/' ], [ 'Octave', '1996-2018 John W. Eaton', diff --git a/assets/javascripts/vendor/prism.js b/assets/javascripts/vendor/prism.js index 86fbb074..608f999c 100644 --- a/assets/javascripts/vendor/prism.js +++ b/assets/javascripts/vendor/prism.js @@ -1,12 +1,12 @@ -/* PrismJS 1.19.0 -https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript+bash+c+cpp+coffeescript+crystal+d+dart+django+elixir+erlang+go+groovy+java+json+julia+kotlin+lua+markup-templating+matlab+nginx+nim+perl+php+python+jsx+ruby+rust+scss+shell-session+sql+typescript+yaml */ +/* PrismJS 1.20.0 +https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript+bash+c+cpp+coffeescript+crystal+d+dart+django+elixir+erlang+go+groovy+java+json+julia+kotlin+lua+markup-templating+matlab+nginx+nim+ocaml+perl+php+python+jsx+ruby+rust+scss+shell-session+sql+typescript+yaml */ var _self = (typeof window !== 'undefined') - ? window // if in browser - : ( - (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) - ? self // if in worker - : {} // if in node js - ); + ? window // if in browser + : ( + (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) + ? self // if in worker + : {} // if in node js + ); /** * Prism: Lightweight, robust, elegant syntax highlighting @@ -22,591 +22,695 @@ var uniqueId = 0; var _ = { - manual: _self.Prism && _self.Prism.manual, - disableWorkerMessageHandler: _self.Prism && _self.Prism.disableWorkerMessageHandler, - util: { - encode: function (tokens) { - if (tokens instanceof Token) { - return new Token(tokens.type, _.util.encode(tokens.content), tokens.alias); - } else if (Array.isArray(tokens)) { - return tokens.map(_.util.encode); - } else { - return tokens.replace(/&/g, '&').replace(/ text.length) { - // Something went terribly wrong, ABORT, ABORT! - return; - } - - if (str instanceof Token) { - continue; - } - - if (greedy && i != strarr.length - 1) { - pattern.lastIndex = pos; - var match = pattern.exec(text); - if (!match) { - break; - } - - var from = match.index + (lookbehind && match[1] ? match[1].length : 0), - to = match.index + match[0].length, - k = i, - p = pos; - - for (var len = strarr.length; k < len && (p < to || (!strarr[k].type && !strarr[k - 1].greedy)); ++k) { - p += strarr[k].length; - // Move the index i to the element in strarr that is closest to from - if (from >= p) { - ++i; - pos = p; - } - } - - // If strarr[i] is a Token, then the match starts inside another Token, which is invalid - if (strarr[i] instanceof Token) { - continue; - } - - // Number of tokens to delete and replace with the new match - delNum = k - i; - str = text.slice(pos, p); - match.index -= pos; - } else { - pattern.lastIndex = 0; - - var match = pattern.exec(str), - delNum = 1; - } - - if (!match) { - if (oneshot) { - break; - } - - continue; - } - - if(lookbehind) { - lookbehindLength = match[1] ? match[1].length : 0; - } - - var from = match.index + lookbehindLength, - match = match[0].slice(lookbehindLength), - to = from + match.length, - before = str.slice(0, from), - after = str.slice(to); - - var args = [i, delNum]; + manual: _self.Prism && _self.Prism.manual, + disableWorkerMessageHandler: _self.Prism && _self.Prism.disableWorkerMessageHandler, + util: { + encode: function encode(tokens) { + if (tokens instanceof Token) { + return new Token(tokens.type, encode(tokens.content), tokens.alias); + } else if (Array.isArray(tokens)) { + return tokens.map(encode); + } else { + return tokens.replace(/&/g, '&').replace(/' + env.content + ''; +}; - run: function (name, env) { - var callbacks = _.hooks.all[name]; +/** + * @param {string} text + * @param {LinkedList} tokenList + * @param {any} grammar + * @param {LinkedListNode} startNode + * @param {number} startPos + * @param {boolean} [oneshot=false] + * @param {string} [target] + */ +function matchGrammar(text, tokenList, grammar, startNode, startPos, oneshot, target) { + for (var token in grammar) { + if (!grammar.hasOwnProperty(token) || !grammar[token]) { + continue; + } + + var patterns = grammar[token]; + patterns = Array.isArray(patterns) ? patterns : [patterns]; + + for (var j = 0; j < patterns.length; ++j) { + if (target && target == token + ',' + j) { + return; + } + + var pattern = patterns[j], + inside = pattern.inside, + lookbehind = !!pattern.lookbehind, + greedy = !!pattern.greedy, + lookbehindLength = 0, + alias = pattern.alias; + + if (greedy && !pattern.pattern.global) { + // Without the global flag, lastIndex won't work + var flags = pattern.pattern.toString().match(/[imsuy]*$/)[0]; + pattern.pattern = RegExp(pattern.pattern.source, flags + 'g'); + } + + pattern = pattern.pattern || pattern; + + for ( // iterate the token list and keep track of the current token/string position + var currentNode = startNode.next, pos = startPos; + currentNode !== tokenList.tail; + pos += currentNode.value.length, currentNode = currentNode.next + ) { + + var str = currentNode.value; + + if (tokenList.length > text.length) { + // Something went terribly wrong, ABORT, ABORT! + return; + } + + if (str instanceof Token) { + continue; + } + + var removeCount = 1; // this is the to parameter of removeBetween + + if (greedy && currentNode != tokenList.tail.prev) { + pattern.lastIndex = pos; + var match = pattern.exec(text); + if (!match) { + break; + } + + var from = match.index + (lookbehind && match[1] ? match[1].length : 0); + var to = match.index + match[0].length; + var p = pos; + + // find the node that contains the match + p += currentNode.value.length; + while (from >= p) { + currentNode = currentNode.next; + p += currentNode.value.length; + } + // adjust pos (and p) + p -= currentNode.value.length; + pos = p; + + // the current node is a Token, then the match starts inside another Token, which is invalid + if (currentNode.value instanceof Token) { + continue; + } + + // find the last node which is affected by this match + for ( + var k = currentNode; + k !== tokenList.tail && (p < to || (typeof k.value === 'string' && !k.prev.value.greedy)); + k = k.next + ) { + removeCount++; + p += k.value.length; + } + removeCount--; + + // replace with the new match + str = text.slice(pos, p); + match.index -= pos; + } else { + pattern.lastIndex = 0; + + var match = pattern.exec(str); + } + + if (!match) { + if (oneshot) { + break; + } + + continue; + } + + if (lookbehind) { + lookbehindLength = match[1] ? match[1].length : 0; + } + + var from = match.index + lookbehindLength, + match = match[0].slice(lookbehindLength), + to = from + match.length, + before = str.slice(0, from), + after = str.slice(to); + + var removeFrom = currentNode.prev; + + if (before) { + removeFrom = addAfter(tokenList, removeFrom, before); + pos += before.length; + } + + removeRange(tokenList, removeFrom, removeCount); + + var wrapped = new Token(token, inside ? _.tokenize(match, inside) : match, alias, match, greedy); + currentNode = addAfter(tokenList, removeFrom, wrapped); + + if (after) { + addAfter(tokenList, currentNode, after); + } + + + if (removeCount > 1) + matchGrammar(text, tokenList, grammar, currentNode.prev, pos, true, token + ',' + j); + + if (oneshot) + break; + } + } + } +} - if (!callbacks || !callbacks.length) { - return; - } +/** + * @typedef LinkedListNode + * @property {T} value + * @property {LinkedListNode | null} prev The previous node. + * @property {LinkedListNode | null} next The next node. + * @template T + */ - for (var i=0, callback; callback = callbacks[i++];) { - callback(env); - } - } - }, +/** + * @template T + */ +function LinkedList() { + /** @type {LinkedListNode} */ + var head = { value: null, prev: null, next: null }; + /** @type {LinkedListNode} */ + var tail = { value: null, prev: head, next: null }; + head.next = tail; + + /** @type {LinkedListNode} */ + this.head = head; + /** @type {LinkedListNode} */ + this.tail = tail; + this.length = 0; +} - Token: Token -}; +/** + * Adds a new node with the given value to the list. + * @param {LinkedList} list + * @param {LinkedListNode} node + * @param {T} value + * @returns {LinkedListNode} The added node. + * @template T + */ +function addAfter(list, node, value) { + // assumes that node != list.tail && values.length >= 0 + var next = node.next; -_self.Prism = _; + var newNode = { value: value, prev: node, next: next }; + node.next = newNode; + next.prev = newNode; + list.length++; -function Token(type, content, alias, matchedStr, greedy) { - this.type = type; - this.content = content; - this.alias = alias; - // Copy of the full string this token was created from - this.length = (matchedStr || '').length|0; - this.greedy = !!greedy; + return newNode; +} +/** + * Removes `count` nodes after the given node. The given node will not be removed. + * @param {LinkedList} list + * @param {LinkedListNode} node + * @param {number} count + * @template T + */ +function removeRange(list, node, count) { + var next = node.next; + for (var i = 0; i < count && next !== list.tail; i++) { + next = next.next; + } + node.next = next; + next.prev = node; + list.length -= i; +} +/** + * @param {LinkedList} list + * @returns {T[]} + * @template T + */ +function toArray(list) { + var array = []; + var node = list.head.next; + while (node !== list.tail) { + array.push(node.value); + node = node.next; + } + return array; } -Token.stringify = function(o, language) { - if (typeof o == 'string') { - return o; - } - - if (Array.isArray(o)) { - return o.map(function(element) { - return Token.stringify(element, language); - }).join(''); - } - - var env = { - type: o.type, - content: Token.stringify(o.content, language), - tag: 'span', - classes: ['token', o.type], - attributes: {}, - language: language - }; - - if (o.alias) { - var aliases = Array.isArray(o.alias) ? o.alias : [o.alias]; - Array.prototype.push.apply(env.classes, aliases); - } - - _.hooks.run('wrap', env); - - var attributes = Object.keys(env.attributes).map(function(name) { - return name + '="' + (env.attributes[name] || '').replace(/"/g, '"') + '"'; - }).join(' '); - - return '<' + env.tag + ' class="' + env.classes.join(' ') + '"' + (attributes ? ' ' + attributes : '') + '>' + env.content + ''; -}; if (!_self.document) { - if (!_self.addEventListener) { - // in Node.js - return _; - } - - if (!_.disableWorkerMessageHandler) { - // In worker - _self.addEventListener('message', function (evt) { - var message = JSON.parse(evt.data), - lang = message.language, - code = message.code, - immediateClose = message.immediateClose; - - _self.postMessage(_.highlight(code, _.languages[lang], lang)); - if (immediateClose) { - _self.close(); - } - }, false); - } - - return _; + if (!_self.addEventListener) { + // in Node.js + return _; + } + + if (!_.disableWorkerMessageHandler) { + // In worker + _self.addEventListener('message', function (evt) { + var message = JSON.parse(evt.data), + lang = message.language, + code = message.code, + immediateClose = message.immediateClose; + + _self.postMessage(_.highlight(code, _.languages[lang], lang)); + if (immediateClose) { + _self.close(); + } + }, false); + } + + return _; } //Get current script and highlight var script = _.util.currentScript(); if (script) { - _.filename = script.src; + _.filename = script.src; + + if (script.hasAttribute('data-manual')) { + _.manual = true; + } +} - if (script.hasAttribute('data-manual')) { - _.manual = true; - } +function highlightAutomaticallyCallback() { + if (!_.manual) { + _.highlightAll(); + } } if (!_.manual) { - function highlightAutomaticallyCallback() { - if (!_.manual) { - _.highlightAll(); - } - } - - // If the document state is "loading", then we'll use DOMContentLoaded. - // If the document state is "interactive" and the prism.js script is deferred, then we'll also use the - // DOMContentLoaded event because there might be some plugins or languages which have also been deferred and they - // might take longer one animation frame to execute which can create a race condition where only some plugins have - // been loaded when Prism.highlightAll() is executed, depending on how fast resources are loaded. - // See https://github.com/PrismJS/prism/issues/2102 - var readyState = document.readyState; - if (readyState === 'loading' || readyState === 'interactive' && script && script.defer) { - document.addEventListener('DOMContentLoaded', highlightAutomaticallyCallback); - } else { - if (window.requestAnimationFrame) { - window.requestAnimationFrame(highlightAutomaticallyCallback); - } else { - window.setTimeout(highlightAutomaticallyCallback, 16); - } - } + // If the document state is "loading", then we'll use DOMContentLoaded. + // If the document state is "interactive" and the prism.js script is deferred, then we'll also use the + // DOMContentLoaded event because there might be some plugins or languages which have also been deferred and they + // might take longer one animation frame to execute which can create a race condition where only some plugins have + // been loaded when Prism.highlightAll() is executed, depending on how fast resources are loaded. + // See https://github.com/PrismJS/prism/issues/2102 + var readyState = document.readyState; + if (readyState === 'loading' || readyState === 'interactive' && script && script.defer) { + document.addEventListener('DOMContentLoaded', highlightAutomaticallyCallback); + } else { + if (window.requestAnimationFrame) { + window.requestAnimationFrame(highlightAutomaticallyCallback); + } else { + window.setTimeout(highlightAutomaticallyCallback, 16); + } + } } return _; @@ -614,642 +718,724 @@ return _; })(_self); if (typeof module !== 'undefined' && module.exports) { - module.exports = Prism; + module.exports = Prism; } // hack for components to work correctly in node.js if (typeof global !== 'undefined') { - global.Prism = Prism; + global.Prism = Prism; } ; Prism.languages.markup = { - 'comment': //, - 'prolog': /<\?[\s\S]+?\?>/, - 'doctype': { - pattern: /"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:(?!)*\]\s*)?>/i, - greedy: true - }, - 'cdata': //i, - 'tag': { - pattern: /<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/i, - greedy: true, - inside: { - 'tag': { - pattern: /^<\/?[^\s>\/]+/i, - inside: { - 'punctuation': /^<\/?/, - 'namespace': /^[^\s>\/:]+:/ - } - }, - 'attr-value': { - pattern: /=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/i, - inside: { - 'punctuation': [ - /^=/, - { - pattern: /^(\s*)["']|["']$/, - lookbehind: true - } - ] - } - }, - 'punctuation': /\/?>/, - 'attr-name': { - pattern: /[^\s>\/]+/, - inside: { - 'namespace': /^[^\s>\/:]+:/ - } - } - - } - }, - 'entity': /&#?[\da-z]{1,8};/i + 'comment': //, + 'prolog': /<\?[\s\S]+?\?>/, + 'doctype': { + // https://www.w3.org/TR/xml/#NT-doctypedecl + pattern: /"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|)*\]\s*)?>/i, + greedy: true, + inside: { + 'internal-subset': { + pattern: /(\[)[\s\S]+(?=\]>$)/, + lookbehind: true, + greedy: true, + inside: null // see below + }, + 'string': { + pattern: /"[^"]*"|'[^']*'/, + greedy: true + }, + 'punctuation': /^$|[[\]]/, + 'doctype-tag': /^DOCTYPE/, + 'name': /[^\s<>'"]+/ + } + }, + 'cdata': //i, + 'tag': { + pattern: /<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/, + greedy: true, + inside: { + 'tag': { + pattern: /^<\/?[^\s>\/]+/, + inside: { + 'punctuation': /^<\/?/, + 'namespace': /^[^\s>\/:]+:/ + } + }, + 'attr-value': { + pattern: /=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/, + inside: { + 'punctuation': [ + { + pattern: /^=/, + alias: 'attr-equals' + }, + /"|'/ + ] + } + }, + 'punctuation': /\/?>/, + 'attr-name': { + pattern: /[^\s>\/]+/, + inside: { + 'namespace': /^[^\s>\/:]+:/ + } + } + + } + }, + 'entity': [ + { + pattern: /&[\da-z]{1,8};/i, + alias: 'named-entity' + }, + /&#x?[\da-f]{1,8};/i + ] }; Prism.languages.markup['tag'].inside['attr-value'].inside['entity'] = - Prism.languages.markup['entity']; + Prism.languages.markup['entity']; +Prism.languages.markup['doctype'].inside['internal-subset'].inside = Prism.languages.markup; // Plugin to make entity title show the real entity, idea by Roman Komarov -Prism.hooks.add('wrap', function(env) { +Prism.hooks.add('wrap', function (env) { - if (env.type === 'entity') { - env.attributes['title'] = env.content.replace(/&/, '&'); - } + if (env.type === 'entity') { + env.attributes['title'] = env.content.replace(/&/, '&'); + } }); Object.defineProperty(Prism.languages.markup.tag, 'addInlined', { - /** - * Adds an inlined language to markup. - * - * An example of an inlined language is CSS with `