mirror of
https://github.com/GitJournal/GitJournal.git
synced 2025-06-28 18:03:14 +08:00
Move links parsing from the markdown string to another thread
This can be very expensive and the UI hands for a large number of notes, otherwise.
This commit is contained in:
100
lib/core/links_loader.dart
Normal file
100
lib/core/links_loader.dart
Normal file
@ -0,0 +1,100 @@
|
||||
import 'dart:io';
|
||||
import 'dart:isolate';
|
||||
|
||||
import 'package:gitjournal/core/link.dart';
|
||||
import 'package:synchronized/synchronized.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
|
||||
import 'package:markdown/markdown.dart' as md;
|
||||
|
||||
class LinksLoader {
|
||||
Isolate _isolate;
|
||||
ReceivePort _receivePort = ReceivePort();
|
||||
SendPort _sendPort;
|
||||
|
||||
var _loadingLock = Lock();
|
||||
|
||||
Future<void> _initIsolate() async {
|
||||
if (_isolate != null && _sendPort != null) return;
|
||||
|
||||
return await _loadingLock.synchronized(() async {
|
||||
if (_isolate != null && _sendPort != null) return;
|
||||
if (_isolate != null) {
|
||||
_isolate.kill(priority: Isolate.immediate);
|
||||
_isolate = null;
|
||||
}
|
||||
_isolate = await Isolate.spawn(_isolateMain, _receivePort.sendPort);
|
||||
|
||||
var data = await _receivePort.first;
|
||||
assert(data is SendPort);
|
||||
_sendPort = data as SendPort;
|
||||
});
|
||||
}
|
||||
|
||||
Future<List<Link>> parseLinks(String body, String parentFolderPath) async {
|
||||
await _initIsolate();
|
||||
|
||||
var rec = ReceivePort();
|
||||
_sendPort.send(_LoadingMessage(body, parentFolderPath, rec.sendPort));
|
||||
|
||||
var data = await rec.first;
|
||||
assert(data is List<Link>);
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
class _LoadingMessage {
|
||||
String body;
|
||||
String parentFolderPath;
|
||||
SendPort sendPort;
|
||||
|
||||
_LoadingMessage(this.body, this.parentFolderPath, this.sendPort);
|
||||
}
|
||||
|
||||
void _isolateMain(SendPort toMainSender) {
|
||||
ReceivePort fromMainRec = ReceivePort();
|
||||
toMainSender.send(fromMainRec.sendPort);
|
||||
|
||||
fromMainRec.listen((data) async {
|
||||
assert(data is _LoadingMessage);
|
||||
var msg = data as _LoadingMessage;
|
||||
|
||||
var links = _parseLinks(msg.body, msg.parentFolderPath);
|
||||
msg.sendPort.send(links);
|
||||
});
|
||||
}
|
||||
|
||||
List<Link> _parseLinks(String body, String parentFolderPath) {
|
||||
final doc = md.Document(
|
||||
encodeHtml: false,
|
||||
extensionSet: md.ExtensionSet.gitHubFlavored,
|
||||
inlineSyntaxes: [WikiLinkSyntax()],
|
||||
);
|
||||
|
||||
var lines = body.replaceAll('\r\n', '\n').split('\n');
|
||||
var nodes = doc.parseLines(lines);
|
||||
var possibleLinks = LinkExtractor().visit(nodes);
|
||||
|
||||
var links = <Link>[];
|
||||
for (var l in possibleLinks) {
|
||||
var path = l.filePath;
|
||||
if (path == null) {
|
||||
links.add(l);
|
||||
continue;
|
||||
}
|
||||
|
||||
var isLocal = !path.contains('://');
|
||||
if (isLocal) {
|
||||
l.filePath = p.join(parentFolderPath, p.normalize(l.filePath));
|
||||
links.add(l);
|
||||
}
|
||||
}
|
||||
|
||||
doc.linkReferences.forEach((key, value) {
|
||||
var filePath = value.destination;
|
||||
links.add(Link(term: key, filePath: filePath));
|
||||
});
|
||||
|
||||
return links;
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:gitjournal/core/md_yaml_doc_loader.dart';
|
||||
import 'package:gitjournal/core/links_loader.dart';
|
||||
import 'package:gitjournal/core/note_notifier.dart';
|
||||
import 'package:gitjournal/core/notes_folder_fs.dart';
|
||||
import 'package:gitjournal/error_reporting.dart';
|
||||
@ -11,7 +12,6 @@ import 'package:gitjournal/utils/datetime.dart';
|
||||
|
||||
import 'package:path/path.dart' as p;
|
||||
|
||||
import 'package:markdown/markdown.dart' as md;
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
import 'link.dart';
|
||||
@ -64,6 +64,7 @@ class Note with NotesNotifier {
|
||||
List<Link> _links;
|
||||
|
||||
static final _mdYamlDocLoader = MdYamlDocLoader();
|
||||
static final _linksLoader = LinksLoader();
|
||||
|
||||
Note(this.parent, this._filePath);
|
||||
|
||||
@ -455,38 +456,8 @@ class Note with NotesNotifier {
|
||||
return _links;
|
||||
}
|
||||
|
||||
final doc = md.Document(
|
||||
encodeHtml: false,
|
||||
extensionSet: md.ExtensionSet.gitHubFlavored,
|
||||
inlineSyntaxes: [WikiLinkSyntax()],
|
||||
);
|
||||
|
||||
var lines = body.replaceAll('\r\n', '\n').split('\n');
|
||||
var nodes = doc.parseLines(lines);
|
||||
var possibleLinks = LinkExtractor().visit(nodes);
|
||||
|
||||
var links = <Link>[];
|
||||
for (var l in possibleLinks) {
|
||||
var path = l.filePath;
|
||||
if (path == null) {
|
||||
links.add(l);
|
||||
continue;
|
||||
}
|
||||
|
||||
var isLocal = !path.contains('://');
|
||||
if (isLocal) {
|
||||
l.filePath = p.join(parent.folderPath, p.normalize(l.filePath));
|
||||
links.add(l);
|
||||
}
|
||||
}
|
||||
|
||||
doc.linkReferences.forEach((key, value) {
|
||||
var filePath = value.destination;
|
||||
links.add(Link(term: key, filePath: filePath));
|
||||
});
|
||||
|
||||
_links = links;
|
||||
return links;
|
||||
_links = await _linksLoader.parseLinks(_body, parent.folderPath);
|
||||
return _links;
|
||||
}
|
||||
|
||||
List<Link> links() {
|
||||
|
35
test/links_loader_test.dart
Normal file
35
test/links_loader_test.dart
Normal file
@ -0,0 +1,35 @@
|
||||
import 'package:gitjournal/core/links_loader.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
group('LinksLoader', () {
|
||||
var contents = """[[GitJournal]]
|
||||
|
||||
[GitJournal](./gitjournal.md)
|
||||
[GitJournal](gitjournal.md)
|
||||
[GitJournal](gitjournal)
|
||||
|
||||
[Google](https://google.com)
|
||||
|
||||
""";
|
||||
|
||||
test('Should load links', () async {
|
||||
var loader = LinksLoader();
|
||||
var links = await loader.parseLinks(contents, "/tmp/foo");
|
||||
|
||||
expect(links[0].filePath, null);
|
||||
expect(links[0].term, "GitJournal");
|
||||
|
||||
expect(links[1].filePath, "/tmp/foo/gitjournal.md");
|
||||
expect(links[1].term, "GitJournal");
|
||||
|
||||
expect(links[2].filePath, "/tmp/foo/gitjournal.md");
|
||||
expect(links[2].term, "GitJournal");
|
||||
|
||||
expect(links[3].filePath, "/tmp/foo/gitjournal");
|
||||
expect(links[3].term, "GitJournal");
|
||||
|
||||
expect(links.length, 4);
|
||||
});
|
||||
});
|
||||
}
|
Reference in New Issue
Block a user