mirror of
https://github.com/wassname/nvatom.git
synced 2026-07-17 01:30:16 +08:00
Replace docquery to note-watcher, which supports lunr search index loading
NoteWatcher holds NoteCache, which caches recent notes and file modified time to help search index recovery.
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
fs = require 'fs-plus'
|
||||
path = require 'path'
|
||||
|
||||
# Keeps a track of notes and its modified time.
|
||||
#
|
||||
# It caches recent notes. Note that a note may partially contain its file content. A file system watcher should call
|
||||
# `upsert` and `remove` accordingly once the note cache is created.
|
||||
#
|
||||
# TODO: Is it a good design? On creation, it deals with file system directly. Once it is created, it relies on outer
|
||||
# feedback, instead of monitoring the file system by itself.
|
||||
#
|
||||
module.exports =
|
||||
class NoteCache
|
||||
constructor: (@_baseDirectory, @_maxItem, @_maxNoteLength) ->
|
||||
@_maxItem = @_maxItem ? 100
|
||||
@_maxNoteLength = @_maxNoteLength ? 100
|
||||
@_noteStats = {}
|
||||
@_state = 'init'
|
||||
|
||||
load: (noteStats) ->
|
||||
@_noteStats = noteStats
|
||||
@_state = 'cache'
|
||||
this
|
||||
|
||||
ready: ->
|
||||
@_buildNoteSortedList()
|
||||
@_buildNoteCache()
|
||||
@_assert()
|
||||
@_state = 'ready'
|
||||
this
|
||||
|
||||
toJSON: ->
|
||||
@_assertReady()
|
||||
JSON.stringify(@_noteStats)
|
||||
|
||||
upsert: (noteId, mtime) ->
|
||||
@_noteStats[noteId] = mtime.getTime()
|
||||
return this unless @_state == 'ready'
|
||||
|
||||
if !(noteId in @_noteSortedList)
|
||||
@_noteSortedList.push(noteId)
|
||||
# TODO: Can this be improved?
|
||||
@_noteSortedList.sort(@_noteIdCompare)
|
||||
if @_noteSortedList.indexOf(noteId) < @_maxItem
|
||||
@_noteCache[noteId] = @_buildNote(noteId)
|
||||
if @_noteSortedList.length > @_maxItem and @_noteSortedList[@_maxItem] in Object.keys(@_noteCache)
|
||||
delete @_noteCache[@_noteSortedList[@_maxItem]]
|
||||
@_assert()
|
||||
this
|
||||
|
||||
remove: (noteId) ->
|
||||
delete @_noteStats[noteId]
|
||||
return this unless @_state == 'ready'
|
||||
|
||||
if noteId in Object.keys(@_noteCache)
|
||||
delete @_noteCache[noteId]
|
||||
if @_noteSortedList.length > @_maxItem and !(@_noteSortedList[@_maxItem] in Object.keys(@_noteCache))
|
||||
@_noteCache[@_noteSortedList[@_maxItem]] = @_buildNote(@_noteSortedList[@_maxItem])
|
||||
@_noteSortedList.splice(@_noteSortedList.indexOf(noteId), 1)
|
||||
@_assert()
|
||||
this
|
||||
|
||||
getNote: (noteId) ->
|
||||
@_assertReady()
|
||||
if noteId in @_noteCache then @_noteCache[noteId] else @_buildNote(noteId)
|
||||
|
||||
getRecentNotes: ->
|
||||
@_assertReady()
|
||||
@_noteSortedList
|
||||
.slice(0, @_maxItem)
|
||||
.map((noteId) => @_noteCache[noteId])
|
||||
|
||||
hasNoteId: (noteId) ->
|
||||
@_noteStats.hasOwnProperty(noteId)
|
||||
|
||||
getNoteIds: ->
|
||||
@_noteSortedList ? Object.keys(@_noteStats)
|
||||
|
||||
getModifiedAt: (noteId) ->
|
||||
@_noteStats[noteId]
|
||||
|
||||
length: ->
|
||||
@_assertReady()
|
||||
@_noteSortedList.length
|
||||
|
||||
_assertReady: ->
|
||||
throw new Error "state is not ready; #{@_state}" unless @_state == 'ready'
|
||||
|
||||
_assert: ->
|
||||
throw new Error "cache length is wrong; #{Object.keys(@_noteCache).length} #{@_noteSortedList} #{@_maxItem}" unless Object.keys(@_noteCache).length == Math.min(@_maxItem, @_noteSortedList.length)
|
||||
throw new Error 'list length is wrong' unless @_noteSortedList.length == Object.keys(@_noteStats).length
|
||||
|
||||
# _buildNoteStats: ->
|
||||
# ret = {}
|
||||
# visited = [fs.absolute(@_baseDirectory)]
|
||||
# fs.traverseTreeSync(
|
||||
# @_baseDirectory,
|
||||
# (filePath) =>
|
||||
# fileName = path.basename(filePath)
|
||||
# if @_extensions.indexOf(path.extname(fileName)) >= 0
|
||||
# noteId = path.relative(@_baseDirectory, filePath)
|
||||
# ret[noteId] = fs.statSync(filePath).mtime.getTime()
|
||||
# ,
|
||||
# (directoryPath) =>
|
||||
# return false if fs.absolute(directoryPath) in visited
|
||||
# visited.push(fs.absolute(directoryPath))
|
||||
# return true
|
||||
# )
|
||||
# ret
|
||||
|
||||
_buildNoteSortedList: ->
|
||||
@_noteSortedList = Object.keys(@_noteStats)
|
||||
@_noteSortedList.sort(@_noteIdCompare)
|
||||
|
||||
_buildNoteCache: ->
|
||||
@_noteCache = {}
|
||||
for noteId in @_noteSortedList.slice(0, @_maxItem)
|
||||
@_noteCache[noteId] = @_buildNote(noteId)
|
||||
|
||||
_buildNote: (noteId) ->
|
||||
filePath = path.join(@_baseDirectory, noteId)
|
||||
fileName = path.basename(filePath)
|
||||
# TODO: Verify it is right
|
||||
title = path.basename(fileName, path.extname(fileName))
|
||||
body = ''
|
||||
if fs.existsSync(filePath)
|
||||
# TODO: Read just the first n letters.
|
||||
body = fs.readFileSync(filePath, 'utf8').slice(0, @_maxNoteLength)
|
||||
return { title: title, body: body, filePath: filePath, modifiedAt: fs.statSync(filePath).mtime }
|
||||
|
||||
_noteIdCompare: (a, b) =>
|
||||
if @_noteStats[a] > @_noteStats[b]
|
||||
return -1
|
||||
if @_noteStats[a] < @_noteStats[b]
|
||||
return 1
|
||||
return 0
|
||||
Reference in New Issue
Block a user