diff --git a/lib/utils/link_resolver.dart b/lib/utils/link_resolver.dart new file mode 100644 index 00000000..3a006a46 --- /dev/null +++ b/lib/utils/link_resolver.dart @@ -0,0 +1,57 @@ +import 'package:gitjournal/core/note.dart'; + +class LinkResolver { + final Note inputNote; + + LinkResolver(this.inputNote); + + Note resolve(String link) { + var spec = link; + var parent = inputNote.parent; + + if (link.startsWith('[[') && link.endsWith(']]') && link.length > 4) { + // FIXME: What if the case is different? + spec = link.substring(2, link.length - 2) + ".md"; + } + + if (link.startsWith('./')) { + spec = link.substring(2); + } + + var linkedNote = parent.getNoteWithSpec(spec); + if (linkedNote != null) { + return linkedNote; + } + + if (!spec.endsWith('.md')) { + linkedNote = parent.getNoteWithSpec(spec + '.md'); + if (linkedNote != null) { + return linkedNote; + } + } + + if (!spec.endsWith('.txt')) { + linkedNote = parent.getNoteWithSpec(spec + '.txt'); + if (linkedNote != null) { + return linkedNote; + } + } + + return null; + } +} + +// Test to write +// 1. [[Fire]] resolves to base folder [[Fire.md]] +// 2. [[Fire.md]] resolve to base folder [[Fire.md]] +// 3. [[Hello/Fire]] resolves to Hello/Fire.md +// 4. [[Hello | pipe]] resolves correctly +// 5. [[Hello Dear]] should resolve correctly +// 6. [[Hello Dear ]] check how it works in Obsidian (ignored extra spaces) +// 7. Should resolve to 'txt' files as well + +// Normal Links +// 4. ./Fire.md -> resovles +// 5. Fire.md -> resolves +// 6. Fire2.md -> fails to resolve +// 7. Complex path ../../Foo/../bar/d.md diff --git a/lib/widgets/note_viewer.dart b/lib/widgets/note_viewer.dart index cada0030..4d1d4206 100644 --- a/lib/widgets/note_viewer.dart +++ b/lib/widgets/note_viewer.dart @@ -16,6 +16,7 @@ import 'package:gitjournal/core/notes_folder_fs.dart'; import 'package:gitjournal/folder_views/common.dart'; import 'package:gitjournal/settings.dart'; import 'package:gitjournal/utils.dart'; +import 'package:gitjournal/utils/link_resolver.dart'; import 'package:gitjournal/utils/logger.dart'; import 'package:gitjournal/widgets/editor_scroll_view.dart'; import 'package:gitjournal/widgets/notes_backlinks.dart'; @@ -67,40 +68,15 @@ class NoteViewer extends StatelessWidget { // selectable: false, -> making this true breaks link navigation styleSheet: markdownStyleSheet, onTapLink: (String link) async { - var spec = link; + final linkResolver = LinkResolver(note); - if (link.startsWith('[[') && - link.endsWith(']]') && - link.length > 4) { - // FIXME: What if the case is different? - spec = link.substring(2, link.length - 2) + ".md"; - } - - if (link.startsWith('./')) { - spec = link.substring(2); - } - - var linkedNote = note.parent.getNoteWithSpec(spec); + var linkedNote = linkResolver.resolve(link); if (linkedNote != null) { openNoteEditor(context, linkedNote); return; } - if (!spec.endsWith('.md')) { - linkedNote = note.parent.getNoteWithSpec(spec + '.md'); - if (linkedNote != null) { - openNoteEditor(context, linkedNote); - return; - } - } - if (!spec.endsWith('.txt')) { - linkedNote = note.parent.getNoteWithSpec(spec + '.txt'); - if (linkedNote != null) { - openNoteEditor(context, linkedNote); - return; - } - } - + // External Link try { await launch(link); } catch (e, stackTrace) { diff --git a/test/link_resolver_test.dart b/test/link_resolver_test.dart new file mode 100644 index 00000000..5b58efbb --- /dev/null +++ b/test/link_resolver_test.dart @@ -0,0 +1,52 @@ +import 'dart:io'; + +import 'package:path/path.dart' as p; +import 'package:test/test.dart'; + +import 'package:gitjournal/core/notes_folder_fs.dart'; +import 'package:gitjournal/utils/link_resolver.dart'; + +void main() { + Directory tempDir; + NotesFolderFS rootFolder; + + setUpAll(() async { + tempDir = await Directory.systemTemp.createTemp('__link_resolver__'); + + rootFolder = NotesFolderFS(null, tempDir.path); + + await generateNote(tempDir.path, "Hello.md"); + await generateNote(tempDir.path, "Fire.md"); + + await rootFolder.loadRecursively(); + }); + + tearDownAll(() async { + tempDir.deleteSync(recursive: true); + }); + + test('Should process simple wiki links', () { + var note = rootFolder.notes[0]; + var linkResolver = LinkResolver(note); + + var resolvedNote = linkResolver.resolve('[[Hello]]'); + expect(resolvedNote.filePath, p.join(tempDir.path, 'Hello.md')); + }); +} + +Future generateNote(String basePath, String path) async { + var filePath = p.join(basePath, path); + + // Ensure directory exists + var dirPath = p.basename(filePath); + await Directory(dirPath).create(recursive: true); + + var content = """--- +title: +modified: 2017-02-15T22:41:19+01:00 +--- + +Hello"""; + + return File(filePath).writeAsString(content, flush: true); +} diff --git a/test/markdown_rendering_test.dart b/test/markdown_rendering_test.dart index 82321f39..1b3bba54 100644 --- a/test/markdown_rendering_test.dart +++ b/test/markdown_rendering_test.dart @@ -1,5 +1,5 @@ -import 'package:test/test.dart'; import 'package:markdown/markdown.dart' as md; +import 'package:test/test.dart'; import 'package:gitjournal/widgets/note_viewer.dart';