Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LSP Server Support #58

Open
wants to merge 50 commits into
base: mathpoly
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
781e276
Export webmain to use from typescript
b-studios Feb 28, 2019
359c853
Export more information about labels
b-studios Feb 28, 2019
3e47972
Backport null
b-studios Feb 28, 2019
a7df281
Strip down processing
b-studios Feb 28, 2019
deb8cde
Log warnings in analyze mode
b-studios Mar 5, 2019
5837a88
Allow block extraction in public interface
b-studios Mar 7, 2019
7e3a36b
Add comment
b-studios Mar 7, 2019
dc2841c
Also annotate range information on blocks
b-studios Mar 7, 2019
8e1607c
Fix some copy&paste errors
b-studios Mar 7, 2019
92781d5
Also export ranges of blocks
b-studios Mar 7, 2019
f358e3a
Move LSP api to a separate koka-file
b-studios Mar 8, 2019
6777d34
Move processContent to api
b-studios Mar 8, 2019
7f5a2bc
Fix whitespaces :lipstick:
b-studios Mar 8, 2019
55c53d4
Revert dependency changes
b-studios Mar 8, 2019
b5d21a2
Simplify api.processContent
b-studios Mar 8, 2019
d56b958
Make processContent direct style
b-studios Mar 8, 2019
de9d174
Change signature of markdown to reuse it in API
b-studios Mar 8, 2019
a23c8bf
Write a few more aux files for static math
b-studios Mar 8, 2019
e79590e
Perform includes before running markdown
b-studios Mar 8, 2019
58f30f4
Allow skipping of includes
b-studios Mar 8, 2019
0a116d1
Merge LSP api with old public api for backwards compatability
b-studios Mar 8, 2019
efc9de1
Always provide second argument to avoid problems with trailing brackets
b-studios Mar 14, 2019
1311ab6
fix doi url handling; add acmart bib style support (showISSN etc)
daanx Nov 21, 2019
db35fcc
Merge branch 'master' into lsp
b-studios Nov 22, 2019
a632ee1
update madoko-local for node 12+
daanx Feb 6, 2020
0b9879d
update styles for TexLive1019
daanx Feb 6, 2020
793f4a2
update acmart style
daanx Feb 6, 2020
f3c82f3
update version to 1.7
daanx Feb 6, 2020
7850916
fix \Bbbk error
daanx Feb 6, 2020
b3c0e53
fix rmdirp version
daanx Feb 8, 2020
999c2bc
add support for inline math and code in tables containing `|`
daanx Feb 8, 2020
6fc6d9a
fix decipher on new nodejs
daanx Feb 8, 2020
8e9f15d
fix github login and repo listinq
daanx Feb 8, 2020
e14ee95
update log message
daanx Feb 8, 2020
59380ee
Merge branch 'master' of https://github.com/koka-lang/madoko
daanx Feb 8, 2020
f4d96a2
update version
daanx Feb 8, 2020
b2b5eda
Merge branch 'master' of https://github.com/koka-lang/madoko
daanx Feb 8, 2020
b341e21
fix table reformatting in the web UI with math/code that contains |
daanx Feb 8, 2020
3a8b3b5
update build instructions
daanx Feb 9, 2020
6680cfe
update madoko-local to have more liberal timeouts
daanx Feb 15, 2020
c13412a
enable running dvisvgm in parallel
daanx Feb 15, 2020
0f75f9f
bump to version 1.1.9
daanx Feb 15, 2020
5c877f0
allow math concurrency setting outside sandbox
daanx Feb 15, 2020
f36a7ac
update madoko local
daanx Feb 15, 2020
ee8ac1a
fix build
daanx Feb 15, 2020
572cae4
2 minute process timeout in sandbox mode
daanx Feb 15, 2020
6d582dd
update madoko local with concurrency flag
daanx Feb 15, 2020
8d9806f
add svg-bbox-exact option to speed up svg genaration by default.
daanx Feb 15, 2020
826f5c1
bump version to 1.2.0
daanx Feb 15, 2020
e6cbbf8
Merge master
b-studios Mar 1, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions Jakefile.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,20 @@ task("web", [], function() {
});
},{async:true})

//-----------------------------------------------------
// Tasks: api
//-----------------------------------------------------
desc("build madoko api")
task("api", [], function() {
// fixVersion("web/client/editor.html");
var args = Array.prototype.slice.call(arguments).join(" ")
var cmd = kokaCmd + " -v -l " + args + " " + "api"
jake.logger.log("> " + cmd);
jake.exec(cmd, {interactive: true}, function(err) {
complete();
});
},{async:true})

var localTexDir = "c:/texlive/texmf-local/tex/latex/local";
desc("setup web");
task("justcopy", [], function() {
Expand Down
37 changes: 37 additions & 0 deletions madoko.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
declare module 'madoko' {
type Options = any;
type Position = { path: string, line: number }
type Range = { path: string, from: number, to: number }
type ReferenceInfo = {
id: string,
element: string,
caption: string,
position?: Position
}
type DocumentInfo = {
labels: ReferenceInfo[],
blocks: Block[],
context: any,
log: string
}
type Block = {
kind: string,
// the element id, empty if not present
id: string,
// the tag name, empty if not present
name: string,
// the child nodes
content: Block[],
// the element classes
classes: string[],
// the annotated attributes
attributes: any,
// the range (lines are 1-based and inclusive)
range?: Range
}

export function analyze(
inputName: string,
content: string,
callback: (DocumentInfo) => any): any;
}
53 changes: 28 additions & 25 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
{
"name" : "madoko",
"author" : "Daan Leijen, Microsoft Corp.",
"version" : "1.1.6",
"homepage" : "http://madoko.codeplex.com",
"description" : "Madoko is a fast scholarly Markdown processor written in Koka",
"licenses": [{
"type" : "Apache License 2.0",
"url" : "http://www.apache.org/licenses/LICENSE-2.0.html"
}],
"name": "madoko",
"author": "Daan Leijen, Microsoft Corp.",
"version": "1.1.6",
"homepage": "http://madoko.codeplex.com",
"description": "Madoko is a fast scholarly Markdown processor written in Koka",
"licenses": [
{
"type": "Apache License 2.0",
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
}
],
"keywords": [
"Madoko",
"Markdown",
"LaTeX",
"Koka",
"Microsoft",
"Scholarly",
"Academic"
"Madoko",
"Markdown",
"LaTeX",
"Koka",
"Microsoft",
"Scholarly",
"Academic"
],
"preferGlobal": true,
"main": "./lib/madoko.js",
"main": "./lib/api.js",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here I changed the main file to access analyze instead of madoko. We need to change this to allow both.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I merged the two interfaces and changed it back, so it should be mostly backwards compatible , modulo the change of the return type of markdown:

- (string,options)
+ (string,options,list<block>,formatContext)

"bin": {
"madoko": "./lib/cli.js"
},
Expand All @@ -33,19 +35,20 @@
"readme.md",
"license.txt"
],
"engines" : {
"node": ">=0.10.0"
"types": "madoko.d.ts",
"engines": {
"node": ">=0.10.0"
},
"dependencies": {
"amdefine" : ">=0.0.4",
"requirejs" : ">=2.1",
"mkdirp" : ">=0.3.5"
"amdefine": ">=0.0.4",
"requirejs": ">=2.1",
"mkdirp": ">=0.3.5"
},
"devDependencies": {
"jake" : ">=0.7.6"
"jake": ">=0.7.6"
},
"repository": {
"type": "hg",
"url" : "https://hg.codeplex.com/madoko"
"type": "hg",
"url": "https://hg.codeplex.com/madoko"
}
}
234 changes: 234 additions & 0 deletions src/api.kk
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
module api

import std/dict
import std/regex
import std/log
import std/path

import backports
import version

import block // just for the type block
import formatBlock // just for formatContext
import common // for label, lineMap, and attrs
import inline // for parseLineInfo
import driver // for outputName, processContentLSP
import metadata // for parseMeta
import madoko // for normalizeSource, lastPathSegment
import definitions // for parseBody
import options
import includes


// Types that are part of the public API
// -------------------------------------

// TODO also migrate to range
public struct position (path: string, line: int)

// Line information is 1-based and inclusive.
public struct range (path: string, from: int, to: int)

public struct referenceInfo (
id: string,
element: string,
caption: string,
position: null<position>
)

public struct documentInfo (
labels: vector<referenceInfo>,
blocks: vector<blockInfo>,
// just for debugging purposes we also include the original formatContext
context : formatContext,
log: string
)

// the type of block nodes we export to js / typescript
public struct blockInfo (
// the block kind
kind: string,
// the element id, empty if not present
id: string,
// the tag name, empty if not present
name: string,
// the child nodes
content: vector<blockInfo>,
// the text content
text: string,
// the classes
classes: vector<string>,
// attributes of the block node (like "caption")
attributes: dict<string>,
// TODO also include position and range information.
position: null<range>
)

// Main Entrypoint
// ---------------

// Runs the frontend to parse and analyze the document but does not
// generate an html or tex document.
//
// Resolves includes and also processes those files.
//
// TODO Currently the logs are very sparse... Did I omit too much of the
// processing to catch errors?
public function analyze(
inputName : string, content : string, continue : (documentInfo) -> io ()
) : io () {
printRedirect( fun(s) { log("stdout", s) });

withLog("stdout") {
processContent(inputName, content) fun (blocks, ctx) {
val stdout = getLog("stdout")
val labeledElems = ctx.inlineContext.labels.list().map(labelInfo)
val res = DocumentInfo(vector(labeledElems), blocks.toBlockInfos(inputName), ctx, stdout)
continue(res)
}
}
()
}


function processContent(
inName : string, content : string,
continue : (list<block>, formatContext) -> io ()
) : io () {
// is this ever used?
val outName = "/tmp/madoko/out.mdk"

val searchDirs = [inName.dirname]

val opts0 = Options(
version=version/version,
lineNoWeb=True,
math=Mathoptions(mode = Dynamic), // don't generate math latex
embedLimit=0,
verbose=1,
copyStyles=False)

// running fastMode destroys positioning
val fastMode = False

content.include(fastMode, inName, outName, searchDirs, opts0) fun(icontent0,lmap) {
// remove madoko comments
val icontent = icontent0 //.removeMadokoComments

val opts1 = opts0(lineMap=lmap,
processTimeout=if (opts0.sandbox) then 60000 else opts0.processTimeout,
metadata=opts0.metadata)

// Just extract metadata and symbols (copied from markdownNormal)
// first normalize the input: all tabs to 4 spaces.
val (options, src) = parseMeta(opts1, FmtHtml, icontent.normalizeSource)

val icontext = inlineContext(FmtHtml,
options.metadata.dict,
options.math.dim,
options.embedinfos,
options.citestyle.maybe(citeNumeric, id),
options.sanitize,
options.bench,
options.verbose,
options.math.mode.isStatic,
options.highlight,
options.starBold,
options.sandbox,
options.prettyAlign)

val (warns0, (blocks, fcontext)) = withLog("warning") {
parseBody(
initialFormatContext(icontext, options.lineMap, options.headingBase, options.pedantic, FmtHtml),
options.lineNo,
src,
options.metadata, options.tocDepth, options.sectionBase, options.sectionMax)
}
// TODO don't collect warnings stringly typed.
log("stdout", warns0)
// val warns = fixWarnings(warns0)
// if (warns != "") {
// log("stdout", warns)
// }

continue(blocks, fcontext)
}
}


// Computing position and range information
// ---------------------------------------

function range(attr: attrs, inputName: string): maybe<range> {
match (attr.hasKey("data-line-start")) {
Just(start) -> catch({
val end = attr.lookupKey("data-line-end", start)
val (path, startLine) = start.extractPosition(inputName)
val (_, endLine) = end.extractPosition(inputName)
Just(Range(path, startLine, endLine))
}, fun(exn) { Nothing })
Nothing -> Nothing
}
}

function extractPosition(locationString: string, inputName: string): exn (string, int) {
val locs = (inputName + ":" + locationString).split(";").list
val last = locs.last.split(":")
(last[0], last[1].parseInt.unJust)
}

// we need the inputName to normalize position information
function toBlockInfos(bs: list<block>, inputName: string): div vector<blockInfo> {
vector(bs.map(fun(b){ b.toBlockInfo(inputName) }).concatMaybe)
}

// TODO also include range information in extracted block structure
function toBlockInfo(b: block, inputName: string): div maybe<blockInfo> {
match(b) {
HLine( attrs ) ->
Just(BlockInfo("hline", attrs.name, attrs.elem, vector(), "", vector(attrs.classes), dict(attrs.keyvals), attrs.range(inputName).null))
Para( text, attrs ) ->
Just(BlockInfo("para", attrs.name, attrs.elem, vector(), text, vector(attrs.classes), dict(attrs.keyvals), attrs.range(inputName).null))
Code( text, _, attrs) ->
Just(BlockInfo("code", attrs.name, attrs.elem, vector(), text, vector(attrs.classes), dict(attrs.keyvals), attrs.range(inputName).null))
Quote( content, attrs) ->
Just(BlockInfo("quote", attrs.name, attrs.elem, content.toBlockInfos(inputName), "", vector(attrs.classes), dict(attrs.keyvals), attrs.range(inputName).null))
List( _, content, attrs) ->
Just(BlockInfo("list", attrs.name, attrs.elem, content.toBlockInfos(inputName), "", vector(attrs.classes), dict(attrs.keyvals), attrs.range(inputName).null))
Item( content, attrs) ->
Just(BlockInfo("item", attrs.name, attrs.elem, content.toBlockInfos(inputName), "", vector(attrs.classes), dict(attrs.keyvals), attrs.range(inputName).null))
Heading( _, text, attrs) ->
Just(BlockInfo("heading", attrs.name, attrs.elem, vector(), text, vector(attrs.classes), dict(attrs.keyvals), attrs.range(inputName).null))
// currently table cells are ignored
Table( _, _, _, attrs) ->
Just(BlockInfo("table", attrs.name, attrs.elem, vector(), "", vector(attrs.classes), dict(attrs.keyvals), attrs.range(inputName).null))
Div( content, attrs) ->
Just(BlockInfo("div", attrs.name, attrs.elem, content.toBlockInfos(inputName), "", vector(attrs.classes), dict(attrs.keyvals), attrs.range(inputName).null))
Source( text, _, attrs) ->
Just(BlockInfo("source", attrs.name, attrs.elem, vector(), text, vector(attrs.classes), dict(attrs.keyvals), attrs.range(inputName).null))
// DefLink( id, link) ->
// DefFootnote( id, content) ->
// Empty() ->
// Special( name, value, attrs) ->
// Line( text, _, attrs) ->
_ -> Nothing
}
}


function labelInfo(elem: (string, label)): referenceInfo {
val (id, label) = elem
ReferenceInfo(id, label.element, label.labelCaption, null(label.labelPosition))
}

// TODO change to labelRange
function labelPosition(label : label) : maybe<position> {
match(label.labelAttrs.hasKey("data-line")) { // || label.labelAttrs.hasKey("data-line-first")
Just(info) -> {
val (path, lineno) = parseLineInfo(info)
Just(Position(path.lastPathSegment, lineno))
// if (lineno <= 0 || info.startsWith("0;")) then Nothing else Just((path.lastPathSegment, lineno))
}
Nothing -> Nothing
}
}
32 changes: 32 additions & 0 deletions src/backports.kk
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
module backports

// backporting null from newer Koka versions:

// Abstract type used for passing `null` values to external functions
public type null<a>

// Transform a `:maybe` type to a `:null` type (using `null` for `Nothing`).
public external null(x : maybe<a>) : null<a> {
cs inline "(#1.tag_ == __std_core._maybe_Tag.Nothing ? default(##1) : #1.@value)"
js inline "(#1==null ? null : #1.unJust)"
}

// Transform a `:null` type to a `:maybe` type. Note that it is not
// always the case that `id(x) == maybe(null(x))` (e.g. when `x = Just(Nothing)`).
public external maybe( n : null<a> ) : maybe<a> {
cs inline "(EqualityComparer<##1>.Default.Equals(#1,default(##1)) ? __std_core._maybe<##1>.Nothing_ : new __std_core._maybe<##1>(#1))"
js inline "(#1==null ? $std_core.Nothing : $std_core.Just(#1))"
}

function unjust( m : maybe<a> ) : exn a {
match(m) {
Just(x) -> x
}
}

function (||)( m1 : maybe<a>, m2: maybe<a> ) : maybe<a> {
match(m1) {
Nothing -> m2
_ -> m1
}
}
Loading