mirror of
https://github.com/GitJournal/GitJournal.git
synced 2025-06-30 19:36:25 +08:00
Move LinkResolving code to its own class
It has become sufficiently complex that a number of edge cases need to be tested.
This commit is contained in:
57
lib/utils/link_resolver.dart
Normal file
57
lib/utils/link_resolver.dart
Normal file
@ -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
|
@ -16,6 +16,7 @@ import 'package:gitjournal/core/notes_folder_fs.dart';
|
|||||||
import 'package:gitjournal/folder_views/common.dart';
|
import 'package:gitjournal/folder_views/common.dart';
|
||||||
import 'package:gitjournal/settings.dart';
|
import 'package:gitjournal/settings.dart';
|
||||||
import 'package:gitjournal/utils.dart';
|
import 'package:gitjournal/utils.dart';
|
||||||
|
import 'package:gitjournal/utils/link_resolver.dart';
|
||||||
import 'package:gitjournal/utils/logger.dart';
|
import 'package:gitjournal/utils/logger.dart';
|
||||||
import 'package:gitjournal/widgets/editor_scroll_view.dart';
|
import 'package:gitjournal/widgets/editor_scroll_view.dart';
|
||||||
import 'package:gitjournal/widgets/notes_backlinks.dart';
|
import 'package:gitjournal/widgets/notes_backlinks.dart';
|
||||||
@ -67,40 +68,15 @@ class NoteViewer extends StatelessWidget {
|
|||||||
// selectable: false, -> making this true breaks link navigation
|
// selectable: false, -> making this true breaks link navigation
|
||||||
styleSheet: markdownStyleSheet,
|
styleSheet: markdownStyleSheet,
|
||||||
onTapLink: (String link) async {
|
onTapLink: (String link) async {
|
||||||
var spec = link;
|
final linkResolver = LinkResolver(note);
|
||||||
|
|
||||||
if (link.startsWith('[[') &&
|
var linkedNote = linkResolver.resolve(link);
|
||||||
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);
|
|
||||||
if (linkedNote != null) {
|
if (linkedNote != null) {
|
||||||
openNoteEditor(context, linkedNote);
|
openNoteEditor(context, linkedNote);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!spec.endsWith('.md')) {
|
// External Link
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await launch(link);
|
await launch(link);
|
||||||
} catch (e, stackTrace) {
|
} catch (e, stackTrace) {
|
||||||
|
52
test/link_resolver_test.dart
Normal file
52
test/link_resolver_test.dart
Normal file
@ -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<void> 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);
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
import 'package:test/test.dart';
|
|
||||||
import 'package:markdown/markdown.dart' as md;
|
import 'package:markdown/markdown.dart' as md;
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
import 'package:gitjournal/widgets/note_viewer.dart';
|
import 'package:gitjournal/widgets/note_viewer.dart';
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user