diff --git a/lib/core/links_loader.dart b/lib/core/links_loader.dart new file mode 100644 index 00000000..d0e36bc1 --- /dev/null +++ b/lib/core/links_loader.dart @@ -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 _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> 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); + + 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 _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 = []; + 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; +} diff --git a/lib/core/note.dart b/lib/core/note.dart index e073d369..fb4993f9 100644 --- a/lib/core/note.dart +++ b/lib/core/note.dart @@ -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 _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 = []; - 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 links() { diff --git a/test/links_loader_test.dart b/test/links_loader_test.dart new file mode 100644 index 00000000..46903ab5 --- /dev/null +++ b/test/links_loader_test.dart @@ -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); + }); + }); +}