update eaf package
This commit is contained in:
@@ -19,36 +19,63 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from PyQt5.QtCore import QUrl
|
||||
from PyQt5.QtGui import QColor
|
||||
|
||||
from PyQt5 import QtCore
|
||||
from PyQt5.QtCore import QUrl, QFileSystemWatcher, QTimer
|
||||
from retrying import retry
|
||||
from core.browser import BrowserBuffer
|
||||
from core.utils import PostGui, get_free_port
|
||||
from core.utils import get_free_port
|
||||
from urllib.error import URLError
|
||||
from urllib.request import urlopen
|
||||
from urllib.parse import urlencode
|
||||
import os
|
||||
import subprocess
|
||||
import threading
|
||||
import tempfile
|
||||
|
||||
class AppBuffer(BrowserBuffer):
|
||||
|
||||
def __init__(self, buffer_id, url, config_dir, arguments, emacs_var_dict, module_path):
|
||||
BrowserBuffer.__init__(self, buffer_id, url, config_dir, arguments, emacs_var_dict, module_path, False)
|
||||
|
||||
# Get free port to render markdown.
|
||||
self.port = get_free_port()
|
||||
self.url = url
|
||||
self.preview_file = tempfile.mkstemp(prefix='eaf-', suffix='.html', text=True)[1]
|
||||
self.render_js = os.path.join(os.path.dirname(__file__), "render.js")
|
||||
self.server_port = get_free_port()
|
||||
self.dark_mode = "false"
|
||||
if emacs_var_dict["eaf-markdown-dark-mode"] == "true" or \
|
||||
(emacs_var_dict["eaf-markdown-dark-mode"] == "follow" and emacs_var_dict["eaf-emacs-theme-mode"] == "dark"):
|
||||
self.dark_mode = "true"
|
||||
|
||||
# Start markdown render process.
|
||||
if arguments == "":
|
||||
subprocess.Popen("grip {0} {1}".format(url, self.port), shell=True)
|
||||
else:
|
||||
subprocess.Popen("grip --pass {0} {1} {2}".format(arguments, url, self.port), shell=True)
|
||||
self.draw_progressbar = True
|
||||
|
||||
# Add timer make load markdown preview link after grip process start finish.
|
||||
timer = threading.Timer(2, self.load_markdown_server)
|
||||
timer.start()
|
||||
self.run_render_server()
|
||||
self.render()
|
||||
|
||||
@PostGui()
|
||||
def load_markdown_server(self):
|
||||
self.buffer_widget.setUrl(QUrl("http://localhost:{0}".format(self.port)))
|
||||
self.file_watcher = QFileSystemWatcher()
|
||||
self.file_watcher.fileChanged.connect(self.on_file_changed)
|
||||
self.file_watcher.addPath(url)
|
||||
|
||||
paths = os.path.split(self.url)
|
||||
if len(paths) > 0:
|
||||
self.change_title(paths[-1])
|
||||
def run_render_server(self):
|
||||
args = ["node", self.render_js, str(self.server_port)]
|
||||
subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=False)
|
||||
|
||||
def on_file_changed(self, *args):
|
||||
self.render()
|
||||
|
||||
def retry_if_connection_refused(ex):
|
||||
return isinstance(ex, URLError) and isinstance(ex.reason, ConnectionRefusedError)
|
||||
|
||||
@retry(wait_fixed=500, stop_max_attempt_number=10, retry_on_exception=retry_if_connection_refused)
|
||||
def render(self):
|
||||
params = {
|
||||
"input_file": self.url,
|
||||
"output_file": self.preview_file,
|
||||
"dark_mode": self.dark_mode
|
||||
}
|
||||
url = 'http://localhost:{}?{}'.format(self.server_port, urlencode(params))
|
||||
with urlopen(url) as f:
|
||||
resp = f.read().decode("utf-8")
|
||||
if resp == "ok":
|
||||
self.buffer_widget.load(QUrl.fromLocalFile(self.preview_file))
|
||||
else:
|
||||
self.message_to_emacs.emit("preview failed: {}".format(resp))
|
||||
|
||||
293
lisp/emacs-application-framework/app/markdown-previewer/demo.md
Normal file
293
lisp/emacs-application-framework/app/markdown-previewer/demo.md
Normal file
@@ -0,0 +1,293 @@
|
||||
# Markdown Preview
|
||||
|
||||
markdown compilation test, modified from [remarkable demo](https://jonschlinkert.github.io/remarkable/demo/).
|
||||
|
||||
---
|
||||
|
||||
# h1 Heading
|
||||
|
||||
## h2 Heading
|
||||
|
||||
### h3 Heading
|
||||
|
||||
#### h4 Heading
|
||||
|
||||
##### h5 Heading
|
||||
|
||||
###### h6 Heading
|
||||
|
||||
## Horizontal Rules
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
## Math
|
||||
|
||||
$
|
||||
\left( \begin{array}{ccc}
|
||||
a & b & c \\
|
||||
d & e & f \\
|
||||
g & h & i \end{array} \right)$
|
||||
is given by the formula
|
||||
|
||||
$$
|
||||
\chi(\lambda) = \left| \begin{array}{ccc}
|
||||
\lambda - a & -b & -c \\
|
||||
-d & \lambda - e & -f \\
|
||||
-g & -h & \lambda - i \end{array} \right|
|
||||
$$
|
||||
|
||||
## Diagrams
|
||||
|
||||
```mermaid
|
||||
graph TD;
|
||||
A-->B;
|
||||
A-->C;
|
||||
B-->D;
|
||||
D-->A
|
||||
```
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice->John: Hello John, how are you?
|
||||
loop Healthcheck
|
||||
John->John: Fight against hypochondria
|
||||
end
|
||||
Note right of John: Rational thoughts <br/>prevail...
|
||||
John-->Alice: Great!
|
||||
John->Bob: How about you?
|
||||
Bob-->John: Jolly good!
|
||||
```
|
||||
|
||||
```puml
|
||||
class A {
|
||||
+ init();
|
||||
}
|
||||
```
|
||||
|
||||
## Code Chunk
|
||||
|
||||
```gnuplot {cmd: "gnuplot", output:"html", hide:true, stdin:true}
|
||||
set term svg
|
||||
set title
|
||||
set key outside
|
||||
set title "plot with filledcurve [options]"
|
||||
plot [-10:10] [-5:3] \
|
||||
1.5+sin(x)/x with filledcurve x2, \
|
||||
sin(x)/x with filledcurve, \
|
||||
1+sin(x)/x with lines, \
|
||||
-1+sin(x)/x with filledcurve y1=-2, \
|
||||
-2.5+sin(x)/x with filledcurve xy=-5,-4., \
|
||||
-4.3+sin(x)/x with filledcurve x1, \
|
||||
(x>3.5 ? x/3-3 : 1/0) with filledcurve y2
|
||||
```
|
||||
|
||||
```python {cmd, hide:true, output:"html"}
|
||||
print('hello world')
|
||||
```
|
||||
|
||||
## Typographic replacements
|
||||
|
||||
Enable typographer option to see result.
|
||||
|
||||
(c) (C) (r) (R) (tm) (TM) (p) (P) +-
|
||||
|
||||
test.. test... test..... test?..... test!....
|
||||
|
||||
!!!!!! ???? ,,
|
||||
|
||||
Remarkable -- awesome
|
||||
|
||||
"Smartypants, double quotes"
|
||||
|
||||
'Smartypants, single quotes'
|
||||
|
||||
## Emphasis
|
||||
|
||||
**This is bold text**
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
__This is bold text__
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
*This is italic text*
|
||||
|
||||
_This is italic text_
|
||||
|
||||
~~Deleted text~~
|
||||
|
||||
Superscript: 19^th^
|
||||
|
||||
Subscript: H~2~O
|
||||
|
||||
++Inserted text++
|
||||
|
||||
==Marked text==
|
||||
|
||||
## Blockquotes
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
> Blockquotes can also be nested...
|
||||
>> ...by using additional greater-than signs right next to each other...
|
||||
> > > ...or with spaces between arrows.
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
## Lists
|
||||
|
||||
Unordered
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
+ Create a list by starting a line with `+`, `-`, or `*`
|
||||
+ Sub-lists are made by indenting 2 spaces:
|
||||
- Marker character change forces new list start:
|
||||
* Ac tristique libero volutpat at
|
||||
+ Facilisis in pretium nisl aliquet
|
||||
- Nulla volutpat aliquam velit
|
||||
+ Very easy!
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
Ordered
|
||||
|
||||
1. Lorem ipsum dolor sit amet
|
||||
2. Consectetur adipiscing elit
|
||||
3. Integer molestie lorem at massa
|
||||
|
||||
<!-- -->
|
||||
|
||||
1. You can use sequential numbers...
|
||||
1. ...or keep all the numbers as `1.`
|
||||
|
||||
Start numbering with offset:
|
||||
|
||||
57. foo
|
||||
1. bar
|
||||
|
||||
## Code
|
||||
|
||||
Inline `code`
|
||||
|
||||
Indented code
|
||||
|
||||
// Some comments
|
||||
line 1 of code
|
||||
line 2 of code
|
||||
line 3 of code
|
||||
|
||||
Block code "fences"
|
||||
|
||||
```
|
||||
Sample text here...
|
||||
```
|
||||
|
||||
Syntax highlighting
|
||||
|
||||
```js
|
||||
var foo = function(bar) {
|
||||
return bar++;
|
||||
};
|
||||
|
||||
console.log(foo(5));
|
||||
```
|
||||
|
||||
## Tables
|
||||
|
||||
| Option | Description |
|
||||
| ------ | ------------------------------------------------------------------------- |
|
||||
| data | path to data files to supply the data that will be passed into templates. |
|
||||
| engine | engine to be used for processing templates. Handlebars is the default. |
|
||||
| ext | extension to be used for dest files. |
|
||||
|
||||
Right aligned columns
|
||||
|
||||
| Option | Description |
|
||||
| -----: | ------------------------------------------------------------------------: |
|
||||
| data | path to data files to supply the data that will be passed into templates. |
|
||||
| engine | engine to be used for processing templates. Handlebars is the default. |
|
||||
| ext | extension to be used for dest files. |
|
||||
|
||||
## Links
|
||||
|
||||
[link text](http://dev.nodeca.com)
|
||||
|
||||
[link with title](http://nodeca.github.io/pica/demo/ "title text!")
|
||||
|
||||
Autoconverted link https://github.com/nodeca/pica (enable linkify to see)
|
||||
|
||||
## Images
|
||||
|
||||

|
||||

|
||||
|
||||
Like links, Images also have a footnote style syntax
|
||||
|
||||
![Alt text][id]
|
||||
|
||||
With a reference later in the document defining the URL location:
|
||||
|
||||
[id]: https://octodex.github.com/images/dojocat.jpg "The Dojocat"
|
||||
|
||||
## Footnotes
|
||||
|
||||
Footnote 1 link[^first].
|
||||
|
||||
Footnote 2 link[^second].
|
||||
|
||||
Inline footnote^[Text of inline footnote] definition.
|
||||
|
||||
Duplicated footnote reference[^second].
|
||||
|
||||
[^first]: Footnote **can have markup**
|
||||
|
||||
and multiple paragraphs.
|
||||
|
||||
[^second]: Footnote text.
|
||||
|
||||
## Definition lists
|
||||
|
||||
Term 1
|
||||
|
||||
: Definition 1
|
||||
with lazy continuation.
|
||||
|
||||
Term 2 with _inline markup_
|
||||
|
||||
: Definition 2
|
||||
|
||||
{ some code, part of Definition 2 }
|
||||
|
||||
Third paragraph of definition 2.
|
||||
|
||||
_Compact style:_
|
||||
|
||||
Term 1
|
||||
~ Definition 1
|
||||
|
||||
Term 2
|
||||
~ Definition 2a
|
||||
~ Definition 2b
|
||||
|
||||
## Abbreviations
|
||||
|
||||
This is HTML abbreviation example.
|
||||
|
||||
It converts "HTML", but keep intact partial entries like "xxxHTMLyyy" and so on.
|
||||
|
||||
\*[HTML]: Hyper Text Markup Language
|
||||
|
||||
---
|
||||
|
||||
**Advertisement :)**
|
||||
|
||||
- **[pica](https://nodeca.github.io/pica/demo/)** - high quality and fast image
|
||||
resize in browser.
|
||||
- **[babelfish](https://github.com/nodeca/babelfish/)** - developer friendly
|
||||
i18n with plurals support and easy syntax.
|
||||
|
||||
You'll like those projects! :)
|
||||
1901
lisp/emacs-application-framework/app/markdown-previewer/package-lock.json
generated
Normal file
1901
lisp/emacs-application-framework/app/markdown-previewer/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "eaf-markdown-previewer",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/manateelazycat/emacs-application-framework.git"
|
||||
},
|
||||
"author": "",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"bugs": {
|
||||
"url": "https://github.com/manateelazycat/emacs-application-framework/issues"
|
||||
},
|
||||
"homepage": "https://github.com/manateelazycat/emacs-application-framework#readme",
|
||||
"dependencies": {
|
||||
"@shd101wyy/mume": "^0.6.3"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const os = require("os");
|
||||
const http = require("http");
|
||||
const url = require("url");
|
||||
|
||||
const mume = require("@shd101wyy/mume");
|
||||
|
||||
function readFile(file, options) {
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.readFile(file, options, (error, text) => {
|
||||
if (error) {
|
||||
return reject(error.toString());
|
||||
}
|
||||
else {
|
||||
return resolve(text.toString());
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function writeFile(file, text, options) {
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.writeFile(file, text, options, (error) => {
|
||||
if (error) {
|
||||
return reject(error.toString());
|
||||
}
|
||||
else {
|
||||
return resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function render(inputFile, outputFile, darkMode) {
|
||||
const configPath = path.resolve(os.homedir(), ".mume");
|
||||
await mume.init(configPath);
|
||||
|
||||
const engine = new mume.MarkdownEngine({
|
||||
filePath: inputFile,
|
||||
config: {
|
||||
configPath: configPath,
|
||||
previewTheme: darkMode ? "atom-dark.css" : "atom-light.css",
|
||||
mermaidTheme: darkMode ? "mermaid.dark.css" : "mermaid.css",
|
||||
codeBlockTheme: darkMode ? "atom-dark.css" : "atom-light.css",
|
||||
printBackground: true,
|
||||
enableScriptExecution: true,
|
||||
},
|
||||
});
|
||||
|
||||
const inputString = await readFile(inputFile, {
|
||||
encoding: "utf-8",
|
||||
});
|
||||
let html;
|
||||
let yamlConfig;
|
||||
({ html, yamlConfig } = await engine.parseMD(inputString, {
|
||||
useRelativeFilePath: false,
|
||||
hideFrontMatter: true,
|
||||
isForPreview: false,
|
||||
runAllCodeChunks: true,
|
||||
}));
|
||||
html = await engine.generateHTMLTemplateForExport(html, yamlConfig, {
|
||||
isForPrint: false,
|
||||
isForPrince: false,
|
||||
offline: true,
|
||||
embedLocalImages: false,
|
||||
});
|
||||
|
||||
await writeFile(outputFile, html);
|
||||
}
|
||||
|
||||
async function server_handler(req, resp) {
|
||||
const q = url.parse(req.url, true).query;
|
||||
const inputFile = q.input_file;
|
||||
const outputFile = q.output_file;
|
||||
const darkMode = q.dark_mode == "true";
|
||||
|
||||
resp.writeHead(200, {'Content-Type': 'text/plain'});
|
||||
try {
|
||||
await render(inputFile, outputFile, darkMode);
|
||||
resp.end('ok');
|
||||
} catch (err) {
|
||||
resp.end(err.message);
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const argv = process.argv;
|
||||
const port = Number(argv[2]);
|
||||
http.createServer(server_handler).listen(port);
|
||||
}
|
||||
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user