mirror of
https://github.com/wassname/nvatom.git
synced 2026-09-10 12:21:11 +08:00
Compare commits
58
Commits
v0.1.0
..
feature-30
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ce9869362a | ||
|
|
4e4688fe78 | ||
|
|
0fffc6a6b1 | ||
|
|
547617f485 | ||
|
|
74735eec82 | ||
|
|
fa873af344 | ||
|
|
a31f490a70 | ||
|
|
27f2a5bb8d | ||
|
|
95093df286 | ||
|
|
5e4345f719 | ||
|
|
cee47a8fd7 | ||
|
|
15bf1e741b | ||
|
|
bd19c270b3 | ||
|
|
b5f7ba7b75 | ||
|
|
da888fa461 | ||
|
|
97830b31db | ||
|
|
a06e0127c2 | ||
|
|
cfd9dcef85 | ||
|
|
ca6f9e76a3 | ||
|
|
5e44098ae3 | ||
|
|
a3f5d445c0 | ||
|
|
abb7339a6e | ||
|
|
4ddc133920 | ||
|
|
bca1646f8f | ||
|
|
40e785ef57 | ||
|
|
273d506f38 | ||
|
|
09d0efc06f | ||
|
|
4dd0b518aa | ||
|
|
bdf384f158 | ||
|
|
c2db598f17 | ||
|
|
1e1aa06e3c | ||
|
|
8384b81a04 | ||
|
|
ef3fb73c88 | ||
|
|
6c9752ae25 | ||
|
|
bb80f5e203 | ||
|
|
5f26638a78 | ||
|
|
52937e2f3c | ||
|
|
55631b89ea | ||
|
|
7ae6d1c211 | ||
|
|
56821bccbc | ||
|
|
11a6c37c70 | ||
|
|
ae435d7043 | ||
|
|
03654ac2c6 | ||
|
|
91f4bca077 | ||
|
|
e39334f9fa | ||
|
|
d8e60f9cfc | ||
|
|
95a793f050 | ||
|
|
c15e7e0f96 | ||
|
|
3679cf0a71 | ||
|
|
6207b379eb | ||
|
|
66e03ce0e3 | ||
|
|
f19c613204 | ||
|
|
42eb70ac27 | ||
|
|
a2b81ad570 | ||
|
|
1f91f4d6b5 | ||
|
|
0f269c9216 | ||
|
|
e94430630c | ||
|
|
49c081ed6e |
@@ -1,2 +1,24 @@
|
||||
## 0.8.0
|
||||
- Add a feature to delete an empty note automatically when closing its pane
|
||||
|
||||
## 0.7.0
|
||||
- Add `extensions` setting
|
||||
|
||||
## 0.5.0
|
||||
- Add `useLunrPipeline` setting
|
||||
- Improve autoselect/autocomplete logic
|
||||
- Fix a bug that autocomplete feature does not work
|
||||
|
||||
## 0.4.0
|
||||
- Rename `notational-velocity` to `nvatom`
|
||||
- Copy `notational-velocity` settings/notes on initialization
|
||||
|
||||
## 0.3.0
|
||||
- Fix the bug that the default note directory is within packages directory. If it happens, it **deletes** all of existing notes. If you read this before updating the package, please check your note directory before updating it.
|
||||
|
||||
## 0.2.0
|
||||
- Use DocQuery
|
||||
- Introduce autosave features
|
||||
|
||||
## 0.1.0
|
||||
- First release
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# Notational Velocity for Atom
|
||||
|
||||
*`notational-velocity` package is renamed to `nvatom` package due to a fatal bug. For more info, refer [migration section](#migration).*
|
||||
|
||||
[![Build Status][3]][4]
|
||||
|
||||
[Notational Velocity][1] is an application that stores and retrieves notes.
|
||||
@@ -26,12 +28,43 @@ We do believe Notational Velocity is the precursor of the famous note-taking app
|
||||
|
||||
## Settings
|
||||
|
||||
- `Note Directory`: The directory to archive notes.
|
||||
To configure your note directory, set `nvatom.directory`:
|
||||
|
||||
* Open your `~/.atom/config.cson` file from the menu: *Atom > Open Your Config*
|
||||
* Append the following lines:
|
||||
|
||||
```cson
|
||||
'nvatom':
|
||||
directory: '/path/to/your/notes'
|
||||
```
|
||||
|
||||
The first line should be indented by one step from `*` at the top. If you've
|
||||
kept the default indentation of two spaces, the block above should paste in
|
||||
properly.
|
||||
|
||||
Double-quotes also work.
|
||||
|
||||
## Key Bindings
|
||||
|
||||
- `alt-cmd-l`: Toggles the search view.
|
||||
|
||||
You can also override `cmd-l` if you want to keep your muscle memory from Notational Velocity and nvALT. Just edit your keymap (Atom menu -> Open Your Keymap) and add the following lines:
|
||||
|
||||
```cson
|
||||
'atom-text-editor':
|
||||
'cmd-l': 'unset!'
|
||||
'atom-workspace':
|
||||
'cmd-l': 'nvatom:toggle'
|
||||
```
|
||||
|
||||
## Migration
|
||||
|
||||
v0.1.0 under published package name `notational-velocity` had a fatal bug that sets the default value of its note directory under package directory. In that case, all notes are deleted once the user updates the package, since package directory is overwritten when the user. For more information, refer [#25][6].
|
||||
|
||||
To resolve this problem, we renamed our package name to `nvatom`. Users who have the old `notational-velocity` need to **install `nvatom` package first**, activate the package to automatically migrate the existing notes, and then delete `notational-velocity` package.
|
||||
|
||||
Since keymaps overlap with `notational-velocity`, follow the menu *Packages > nvAtom > Toggle* to activate this package.
|
||||
|
||||
## References
|
||||
|
||||
- [Notational Velocity](http://notational.net/)
|
||||
@@ -43,6 +76,7 @@ We do believe Notational Velocity is the precursor of the famous note-taking app
|
||||
|
||||
[1]: http://notational.net/
|
||||
[2]: http://daringfireball.net/projects/markdown/syntax
|
||||
[3]: https://travis-ci.org/seongjaelee/notational-velocity.svg?branch=master
|
||||
[4]: https://travis-ci.org/seongjaelee/notational-velocity
|
||||
[3]: https://travis-ci.org/seongjaelee/nvatom.svg?branch=master
|
||||
[4]: https://travis-ci.org/seongjaelee/nvatom
|
||||
[5]: https://cloud.githubusercontent.com/assets/948301/7246990/2e2b4c6e-e7b9-11e4-93b0-57954e011e81.gif
|
||||
[6]: https://github.com/seongjaelee/nvatom/issues/25
|
||||
|
||||
@@ -8,4 +8,4 @@
|
||||
# For more detailed documentation see
|
||||
# https://atom.io/docs/latest/advanced/keymaps
|
||||
'atom-workspace':
|
||||
'alt-cmd-l': 'notational-velocity:toggle'
|
||||
'alt-cmd-l': 'nvatom:toggle'
|
||||
|
||||
@@ -1,69 +1,42 @@
|
||||
path = require 'path'
|
||||
fs = require 'fs-plus'
|
||||
_ = require 'underscore-plus'
|
||||
{$, $$, SelectListView} = require 'atom-space-pen-views'
|
||||
NoteDirectory = require './note-directory'
|
||||
Note = require './note'
|
||||
DocQuery = require 'docquery'
|
||||
|
||||
module.exports =
|
||||
class NotationalVelocityView extends SelectListView
|
||||
initialize: ->
|
||||
initialize: (state) ->
|
||||
@initializedAt = new Date()
|
||||
super
|
||||
@addClass('notational-velocity from-top overlay')
|
||||
@rootDirectory = atom.config.get('notational-velocity.directory')
|
||||
if !fs.existsSync(@rootDirectory)
|
||||
@addClass('nvatom from-top overlay')
|
||||
@rootDirectory = atom.config.get('nvatom.directory')
|
||||
unless fs.existsSync(@rootDirectory)
|
||||
throw new Error("The given directory #{@rootDirectory} does not exist. "
|
||||
+ "Set the note directory to the existing one from Settings.")
|
||||
@noteDirectory = new NoteDirectory(@rootDirectory, null, () => @updateNotes())
|
||||
@updateNotes()
|
||||
@prevFilterQuery = ''
|
||||
@skipPopulateList = false
|
||||
@prevCursorPosition = 0
|
||||
@documentsLoaded = false
|
||||
@docQuery = new DocQuery(@rootDirectory, {recursive: true, extensions: atom.config.get('nvatom.extensions')})
|
||||
@docQuery.on "ready", () =>
|
||||
@documentsLoaded = true
|
||||
@setLoading()
|
||||
@populateList()
|
||||
@docQuery.on "added", (fileDetails) =>
|
||||
@populateList() if @documentsLoaded
|
||||
@docQuery.on "updated", (fileDetails) =>
|
||||
@populateList() if @documentsLoaded
|
||||
@docQuery.on "removed", (fileDetails) =>
|
||||
@populateList() if @documentsLoaded
|
||||
unless atom.config.get('nvatom.enableLunrPipeline')
|
||||
@docQuery.searchIndex.pipeline.reset()
|
||||
|
||||
updateNotes: () ->
|
||||
@notes = @noteDirectory.getNotes()
|
||||
@setItems(@notes)
|
||||
|
||||
selectItem: (filterQuery) ->
|
||||
if filterQuery.length == 0
|
||||
@prevCursorPosition = 0
|
||||
return null
|
||||
|
||||
titlePatterns = [
|
||||
///^#{filterQuery}$///i,
|
||||
///^#{filterQuery}///i,
|
||||
]
|
||||
|
||||
titleItem = null
|
||||
for titlePattern in titlePatterns
|
||||
titleItems = @notes
|
||||
.filter (x) -> x.getTitle().match(titlePattern) != null
|
||||
titleItem = if titleItems.length > 0 then titleItems[0] else null
|
||||
if titleItem != null
|
||||
break
|
||||
|
||||
# If title item is not null, auto-fill the search panel.
|
||||
# But we don't want to fill it when deleting.
|
||||
isCursorProceeded: ->
|
||||
editor = @filterEditorView.model
|
||||
currCursorPosition = editor.getCursorBufferPosition().column
|
||||
if titleItem != null && @prevCursorPosition < currCursorPosition
|
||||
@prevFilterQuery = titleItem.getTitle()
|
||||
editor.setText(titleItem.getTitle())
|
||||
editor.selectLeft(titleItem.getTitle().length - filterQuery.length)
|
||||
isCursorProceeded = @prevCursorPosition < currCursorPosition
|
||||
@prevCursorPosition = currCursorPosition
|
||||
|
||||
return titleItem
|
||||
|
||||
filter: (filterQuery) ->
|
||||
if filterQuery.length == 0
|
||||
return @notes
|
||||
|
||||
queries = filterQuery.split(' ')
|
||||
.filter (x) -> x.length > 0
|
||||
.map (x) -> new RegExp(x, 'gi')
|
||||
return @notes
|
||||
.filter (x) ->
|
||||
queries
|
||||
.map (q) -> q.test(x.getText()) || q.test(x.getTitle())
|
||||
.reduce (x, y) -> x && y
|
||||
return isCursorProceeded
|
||||
|
||||
getFilterKey: ->
|
||||
'filetext'
|
||||
@@ -71,32 +44,48 @@ class NotationalVelocityView extends SelectListView
|
||||
toggle: ->
|
||||
if @panel?.isVisible()
|
||||
@hide()
|
||||
else
|
||||
else if @documentsLoaded
|
||||
@populateList()
|
||||
@show()
|
||||
else
|
||||
@setLoading("Loading documents")
|
||||
@show()
|
||||
|
||||
viewForItem: (item) ->
|
||||
content = item.getText()[0...100]
|
||||
content = item.body[0...100]
|
||||
|
||||
$$ ->
|
||||
@li class: 'two-lines', =>
|
||||
@div class: 'primary-line', =>
|
||||
@span "#{item.getTitle()}"
|
||||
@div class: 'metadata', "#{item.getModified().toLocaleDateString()}"
|
||||
@span "#{item.title}"
|
||||
@div class: 'metadata', "#{item.modifiedAt.toLocaleDateString()}"
|
||||
@div class: 'secondary-line', "#{content}"
|
||||
|
||||
confirmSelection: ->
|
||||
item = @getSelectedItem()
|
||||
filePath = null
|
||||
sanitizedQuery = @getFilterQuery().replace(/\s+$/, '')
|
||||
extension = if atom.config.get('nvatom.extensions').length then atom.config.get('nvatom.extensions')[0] else '.md'
|
||||
calculatedPath = path.join(@rootDirectory, sanitizedQuery + extension)
|
||||
if item?
|
||||
atom.workspace.open(item.getFilePath())
|
||||
@cancel()
|
||||
else
|
||||
sanitizedQuery = @getFilterQuery().replace(/\s+$/, '')
|
||||
if sanitizedQuery.length > 0
|
||||
filePath = path.join(@rootDirectory, sanitizedQuery + '.md')
|
||||
fs.writeFileSync(filePath, '')
|
||||
atom.workspace.open(filePath)
|
||||
@cancel()
|
||||
filePath = item.filePath
|
||||
else if fs.existsSync(calculatedPath)
|
||||
filePath = calculatedPath
|
||||
else if sanitizedQuery.length > 0
|
||||
filePath = calculatedPath
|
||||
fs.writeFileSync(filePath, '')
|
||||
|
||||
if filePath
|
||||
atom.workspace.open(filePath).then (editor) ->
|
||||
save = ->
|
||||
atom.packages.deactivatePackage 'whitespace'
|
||||
editor.save()
|
||||
atom.packages.activatePackage 'whitespace'
|
||||
debouncedSave = _.debounce save, 1000
|
||||
editor.onDidStopChanging () ->
|
||||
debouncedSave() if editor.isModified()
|
||||
|
||||
@cancel()
|
||||
|
||||
destroy: ->
|
||||
@cancel()
|
||||
@@ -114,33 +103,81 @@ class NotationalVelocityView extends SelectListView
|
||||
hide: ->
|
||||
@panel?.hide()
|
||||
|
||||
populateList: ->
|
||||
return unless @notes?
|
||||
getFilterQuery: ->
|
||||
editor = @filterEditorView.model
|
||||
fullText = editor.getText()
|
||||
selectedText = editor.getSelectedText()
|
||||
return fullText.substring(0, fullText.length - selectedText.length)
|
||||
|
||||
filterByTitle: (filterQuery) ->
|
||||
if (filterQuery is "") or (filterQuery is undefined)
|
||||
return []
|
||||
filterQuery = filterQuery.toLowerCase()
|
||||
matchingNotes = []
|
||||
filteredNotes = []
|
||||
for note in @docQuery.documents
|
||||
title = note.title.toLowerCase()
|
||||
if title is filterQuery
|
||||
matchingNotes.push(note)
|
||||
else if filteredNotes.length < @maxItems and title.startsWith(filterQuery)
|
||||
filteredNotes.push(note)
|
||||
notes = matchingNotes.concat(filteredNotes)
|
||||
if notes.length > @maxItems
|
||||
notes = notes.slice(0, @maxItems)
|
||||
return notes
|
||||
|
||||
filterByLunr: (filterQuery) ->
|
||||
notes = []
|
||||
if (filterQuery is "") or (filterQuery is undefined)
|
||||
notes = @docQuery.documents
|
||||
else
|
||||
notes = @docQuery.search(filterQuery)
|
||||
if notes.length > @maxItems
|
||||
notes = notes.slice(0, @maxItems)
|
||||
return notes
|
||||
|
||||
populateList: ->
|
||||
filterQuery = @getFilterQuery()
|
||||
filteredItems = @filter(filterQuery)
|
||||
selectedItem = @selectItem(filterQuery)
|
||||
notesByTitle = @filterByTitle(filterQuery)
|
||||
notesByLunr = @filterByLunr(filterQuery)
|
||||
isCursorProceeded = @isCursorProceeded()
|
||||
|
||||
@list.empty()
|
||||
if filteredItems.length
|
||||
@setError(null)
|
||||
if notesByTitle.length + notesByLunr.length == 0
|
||||
@setError(@getEmptyMessage(@docQuery.documents.length, 0))
|
||||
return
|
||||
|
||||
for i in [0...Math.min(filteredItems.length, @maxItems)]
|
||||
item = filteredItems[i]
|
||||
itemView = $(@viewForItem(item))
|
||||
itemView.data('select-list-item', item)
|
||||
@list.append(itemView)
|
||||
@setError(null)
|
||||
for note in notesByTitle
|
||||
itemView = $(@viewForItem(note))
|
||||
itemView.data('select-list-item', note)
|
||||
@list.append(itemView)
|
||||
|
||||
if selectedItem
|
||||
n = filteredItems.indexOf(selectedItem) + 1
|
||||
@selectItemView(@list.find("li:nth-child(#{n})"))
|
||||
if notesByTitle.length
|
||||
# autoselect
|
||||
@selectItemView(@list.find("li:nth-child(1)"))
|
||||
|
||||
else
|
||||
@setError(@getEmptyMessage(@notes.length, filteredItems.length))
|
||||
#autocomplete
|
||||
note = notesByTitle[0]
|
||||
if note.title.toLowerCase() is filterQuery.toLowerCase() or isCursorProceeded
|
||||
@skipPopulateList = true
|
||||
editor = @filterEditorView.model
|
||||
editor.setText(filterQuery + note.title.slice(filterQuery.length))
|
||||
editor.selectLeft(note.title.length - filterQuery.length)
|
||||
|
||||
if @list.length >= @maxItems
|
||||
return
|
||||
|
||||
for note in notesByLunr
|
||||
if @list.length >= @maxItems
|
||||
break
|
||||
if filterQuery?.length and note.title.toLowerCase().startsWith(filterQuery.toLowerCase())
|
||||
continue
|
||||
itemView = $(@viewForItem(note))
|
||||
itemView.data('select-list-item', note)
|
||||
@list.append(itemView)
|
||||
|
||||
schedulePopulateList: ->
|
||||
# We can skip it when we are just moving the position of the cursor.
|
||||
currFilterQuery = @getFilterQuery()
|
||||
if @prevFilterQuery != currFilterQuery
|
||||
unless @skipPopulateList
|
||||
super
|
||||
@prevFilterQuery = currFilterQuery
|
||||
@skipPopulateList = false
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{CompositeDisposable} = require 'atom'
|
||||
path = require 'path'
|
||||
fs = require 'fs-plus'
|
||||
{CompositeDisposable, Disposable} = require 'atom'
|
||||
|
||||
module.exports =
|
||||
config:
|
||||
@@ -6,18 +8,46 @@ module.exports =
|
||||
title: 'Note Directory'
|
||||
description: 'The directory to archive notes'
|
||||
type: 'string'
|
||||
default: process.env.ATOM_HOME + '/packages/notational-velocity/notebook'
|
||||
default: path.join(process.env.ATOM_HOME, 'nvatom-notes')
|
||||
extensions:
|
||||
title: 'Extensions'
|
||||
description: 'The first extension will be used for newly created notes.'
|
||||
type: 'array'
|
||||
default: ['.md', '.txt']
|
||||
items:
|
||||
type: 'string'
|
||||
enableLunrPipeline:
|
||||
title: 'Enable Lunr Pipeline'
|
||||
description: 'Lunr pipeline preprocesses query to make search faster. However, it will skip searching some of stop words such as "an" or "be".'
|
||||
type: 'boolean'
|
||||
default: true
|
||||
|
||||
notationalVelocityView: null
|
||||
|
||||
activate: (state) ->
|
||||
@rootDirectory = @ensureNoteDirectory()
|
||||
|
||||
# Events subscribed to in atom's system can be easily cleaned up with a
|
||||
# CompositeDisposable
|
||||
@subscriptions = new CompositeDisposable
|
||||
|
||||
# Register command that toggles this view
|
||||
@subscriptions.add atom.commands.add 'atom-workspace',
|
||||
'notational-velocity:toggle': => @createView(state).toggle()
|
||||
'nvatom:toggle': => @createView(state).toggle()
|
||||
|
||||
handleBeforeUnload = @autosaveAll.bind(this)
|
||||
window.addEventListener('beforeunload', handleBeforeUnload, true)
|
||||
@subscriptions.add new Disposable -> window.removeEventListener('beforeunload', handleBeforeUnload, true)
|
||||
|
||||
handleBlur = (event) =>
|
||||
if event.target is window
|
||||
@autosaveAll()
|
||||
else if event.target.matches('atom-text-editor:not([mini])') and not event.target.contains(event.relatedTarget)
|
||||
@autosave(event.target.getModel())
|
||||
window.addEventListener('blur', handleBlur, true)
|
||||
@subscriptions.add new Disposable -> window.removeEventListener('blur', handleBlur, true)
|
||||
|
||||
@subscriptions.add atom.workspace.onWillDestroyPaneItem ({item}) => @autosave(item) unless @autodelete(item)
|
||||
|
||||
deactivate: ->
|
||||
@subscriptions.dispose()
|
||||
@@ -26,8 +56,73 @@ module.exports =
|
||||
serialize: ->
|
||||
notationalVelocityViewState: @notationalVelocityView.serialize()
|
||||
|
||||
createView: (state) ->
|
||||
createView: (state, docQuery) ->
|
||||
unless @notationalVelocityView?
|
||||
NotationalVelocityView = require './notational-velocity-view'
|
||||
@notationalVelocityView = new NotationalVelocityView(state.notationalVelocityViewState)
|
||||
@notationalVelocityView
|
||||
|
||||
autosave: (paneItem) ->
|
||||
return unless paneItem?.getURI?()?
|
||||
return unless paneItem?.isModified?()
|
||||
uri = paneItem.getURI()
|
||||
return unless uri.indexOf(@rootDirectory) is 0
|
||||
return unless path.extname(uri) in atom.config.get('nvatom.extensions')
|
||||
paneItem?.save?()
|
||||
|
||||
autodelete: (paneItem) ->
|
||||
return false unless paneItem?.getURI?()?
|
||||
uri = paneItem.getURI()
|
||||
return false unless uri.indexOf(@rootDirectory) is 0
|
||||
return false unless path.extname(uri) in atom.config.get('nvatom.extensions')
|
||||
return false unless paneItem?.isEmpty()
|
||||
fs.unlinkSync(uri)
|
||||
noteName = uri.substring(@rootDirectory.length + 1)
|
||||
atom.notifications.addInfo("Empty note #{noteName} is deleted.")
|
||||
return true
|
||||
|
||||
autosaveAll: ->
|
||||
@autosave(paneItem) for paneItem in atom.workspace.getPaneItems()
|
||||
|
||||
ensureNoteDirectory: ->
|
||||
noteDirectory = atom.config.get('nvatom.directory')
|
||||
packagesDirectory = path.join(process.env.ATOM_HOME, 'packages')
|
||||
defaultNoteDirectory = path.join(packagesDirectory, 'nvatom', 'notebook')
|
||||
|
||||
if noteDirectory.startsWith(packagesDirectory)
|
||||
throw new Error("Note directory #{noteDirectory} cannot reside within atom packages directory. Please change its value from package settings.")
|
||||
|
||||
# Initialize note directory.
|
||||
unless fs.existsSync(noteDirectory)
|
||||
@tryMigrateFromNotationalVelocity()
|
||||
noteDirectory = atom.config.get('nvatom.directory')
|
||||
unless fs.existsSync(noteDirectory)
|
||||
fs.makeTreeSync(noteDirectory)
|
||||
fs.copySync(defaultNoteDirectory, noteDirectory)
|
||||
|
||||
return fs.realpathSync(noteDirectory)
|
||||
|
||||
tryMigrateFromNotationalVelocity: ->
|
||||
prevNoteDirectory = atom.config.get('notational-velocity.directory')
|
||||
currNoteDirectory = atom.config.get('nvatom.directory')
|
||||
packagesDirectory = path.join(process.env.ATOM_HOME, 'packages')
|
||||
defaultNoteDirectory = path.join(packagesDirectory, 'nvatom', 'notebook')
|
||||
|
||||
# notational-velocity does not exist.
|
||||
if prevNoteDirectory is undefined
|
||||
return
|
||||
|
||||
atom.notifications.addInfo('Migrating from notational-velocity package...')
|
||||
|
||||
unless fs.existsSync(prevNoteDirectory)
|
||||
atom.notifications.addError("notational-velocity.directory #{prevNoteDirectory} does not exists. Migration process is failed.")
|
||||
return
|
||||
|
||||
if prevNoteDirectory.startsWith(packagesDirectory)
|
||||
fs.makeTreeSync(currNoteDirectory)
|
||||
fs.copySync(prevNoteDirectory, currNoteDirectory)
|
||||
else
|
||||
if path.join(process.env.ATOM_HOME, 'nvatom-notes') == currNoteDirectory
|
||||
atom.config.set('nvatom.directory', prevNoteDirectory)
|
||||
|
||||
atom.notifications.addInfo('Finished migration.')
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
path = require 'path'
|
||||
fs = require 'fs-plus'
|
||||
pathWatcher = require 'pathwatcher'
|
||||
Note = require './note'
|
||||
|
||||
module.exports =
|
||||
class NoteDirectory
|
||||
constructor: (@filePath, @parent, @onChangeCallback) ->
|
||||
@directories = []
|
||||
@notes = []
|
||||
@updateMetadata()
|
||||
@watcher = pathWatcher.watch(@filePath, (event) => @onChange(event))
|
||||
|
||||
destroy: ->
|
||||
@notes.map (x) -> x.destroy()
|
||||
@directories.map (x) -> x.destroy()
|
||||
@watcher.close()
|
||||
|
||||
updateMetadata: ->
|
||||
@notes.map (x) -> x.destroy()
|
||||
@directories.map (x) -> x.destroy()
|
||||
|
||||
@directories = []
|
||||
@notes = []
|
||||
|
||||
try
|
||||
filenames = fs.readdirSync(@filePath)
|
||||
catch e
|
||||
return
|
||||
for filename in filenames
|
||||
@addChild(path.join(@filePath, filename))
|
||||
|
||||
addChild: (filePath) ->
|
||||
try
|
||||
fileStat = fs.statSync(filePath)
|
||||
catch e
|
||||
return
|
||||
if fileStat.isDirectory()
|
||||
@directories.push(new NoteDirectory(filePath, this, @onChangeCallback))
|
||||
else
|
||||
if fs.isMarkdownExtension(path.extname(filePath))
|
||||
@notes.push(new Note(filePath, this, @onChangeCallback))
|
||||
|
||||
getNotes: ->
|
||||
ret = []
|
||||
ret = ret.concat(@notes)
|
||||
for directory in @directories
|
||||
ret = ret.concat(directory.getNotes())
|
||||
if @parent is null
|
||||
ret.sort (x, y) -> if x.getModified().getTime() <= y.getModified().getTime() then 1 else -1
|
||||
return ret
|
||||
|
||||
onChange: (event) ->
|
||||
# For the case of rename and change, it will be handled in its parent.
|
||||
if event == 'change'
|
||||
@updateMetadata()
|
||||
if @onChangeCallback != null
|
||||
@onChangeCallback()
|
||||
@@ -1,37 +0,0 @@
|
||||
path = require 'path'
|
||||
fs = require 'fs'
|
||||
pathWatcher = require 'pathwatcher'
|
||||
|
||||
module.exports =
|
||||
class Note
|
||||
constructor: (@filePath, @parent, @onChangeCallback) ->
|
||||
@updateMetadata()
|
||||
@updateText()
|
||||
@watcher = pathWatcher.watch(@filePath, (event) => @onChange(event))
|
||||
|
||||
destroy: ->
|
||||
@watcher.close()
|
||||
|
||||
updateMetadata: ->
|
||||
@modified = fs.statSync(@filePath).mtime
|
||||
relativePath = path.relative(atom.config.get('notational-velocity.directory'), @filePath)
|
||||
@title = path.join(
|
||||
path.dirname(relativePath),
|
||||
path.basename(relativePath, path.extname(relativePath))
|
||||
)
|
||||
|
||||
updateText: ->
|
||||
@text = fs.readFileSync(@filePath, 'utf8')
|
||||
|
||||
onChange: (event) ->
|
||||
# For the case of rename and change, it will be handled in its parent.
|
||||
if event == 'change' && fs.existsSync(@filePath)
|
||||
@updateMetadata()
|
||||
@updateText()
|
||||
if @onChangeCallback != null
|
||||
@onChangeCallback()
|
||||
|
||||
getTitle: -> @title
|
||||
getText: -> @text
|
||||
getModified: -> @modified
|
||||
getFilePath: -> @filePath
|
||||
@@ -3,11 +3,11 @@
|
||||
{
|
||||
'label': 'Packages'
|
||||
'submenu': [
|
||||
'label': 'Notational Velocity'
|
||||
'label': 'nvAtom'
|
||||
'submenu': [
|
||||
{
|
||||
'label': 'Toggle'
|
||||
'command': 'notational-velocity:toggle'
|
||||
'command': 'nvatom:toggle'
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
+14
-15
@@ -1,33 +1,32 @@
|
||||
{
|
||||
"name": "notational-velocity",
|
||||
"name": "nvatom",
|
||||
"main": "./lib/notational-velocity",
|
||||
"version": "0.1.0",
|
||||
"version": "0.8.1",
|
||||
"private": true,
|
||||
"contributors": [
|
||||
"Seongjae Lee <seongjaelee@gmail.com>"
|
||||
"Seongjae Lee <seongjae@gmail.com>",
|
||||
"Nikita Litvin <deltaidea@derpy.ru>",
|
||||
"Jonathan Hoyt <hoyt@github.com>"
|
||||
],
|
||||
"description": "Notational Velocity for Atom",
|
||||
"activationCommands": {
|
||||
"atom-workspace": "notational-velocity:toggle"
|
||||
"atom-workspace": "nvatom:toggle"
|
||||
},
|
||||
"repository": "https://github.com/seongjaelee/notational-velocity",
|
||||
"repository": "https://github.com/seongjaelee/nvatom",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"atom": ">0.50.0"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/seongjaelee/notational-velocity/issues"
|
||||
"url": "https://github.com/seongjaelee/nvatom/issues"
|
||||
},
|
||||
"homepage": "https://github.com/seongjaelee/notational-velocity",
|
||||
"homepage": "https://github.com/seongjaelee/nvatom",
|
||||
"dependencies": {
|
||||
"fs-plus": "2.x",
|
||||
"atom-space-pen-views": "^2.0.3",
|
||||
"pathwatcher": "^4.2"
|
||||
"chokidar": "^1.0.5",
|
||||
"docquery": "^1.1.0",
|
||||
"fs-plus": "2.x",
|
||||
"underscore-plus": "^1.6.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"fs-plus": "2.x",
|
||||
"atom-space-pen-views": "^2.0.3",
|
||||
"pathwatcher": "^4.2",
|
||||
"temp": "~0.7.0"
|
||||
}
|
||||
"devDependencies": {}
|
||||
}
|
||||
|
||||
@@ -1,34 +1,49 @@
|
||||
{WorkspaceView} = require 'atom'
|
||||
NotationalVelocity = require '../lib/notational-velocity'
|
||||
path = require 'path'
|
||||
|
||||
# Use the command `window:run-package-specs` (cmd-alt-ctrl-p) to run specs.
|
||||
#
|
||||
# To run a specific `it` or `describe` block add an `f` to the front (e.g. `fit`
|
||||
# or `fdescribe`). Remove the `f` to unfocus the block.
|
||||
|
||||
describe "NotationalVelocity", ->
|
||||
defaultDirectory = atom.config.get('notational-velocity.directory')
|
||||
describe "nvAtom", ->
|
||||
defaultDirectory = atom.config.get('nvatom.directory')
|
||||
activationPromise = null
|
||||
workspaceElement = null
|
||||
|
||||
beforeEach ->
|
||||
atom.workspaceView = new WorkspaceView
|
||||
activationPromise = atom.packages.activatePackage('notational-velocity')
|
||||
atom.config.set('notational-velocity.directory', 'testdata')
|
||||
workspaceElement = atom.views.getView(atom.workspace)
|
||||
activationPromise = atom.packages.activatePackage('nvatom')
|
||||
atom.config.set('nvatom.directory', 'testdata')
|
||||
|
||||
afterEach ->
|
||||
atom.config.set('notational-velocity.directory', defaultDirectory)
|
||||
atom.config.set('nvatom.directory', defaultDirectory)
|
||||
|
||||
describe "when the notational-velocity:toggle event is triggered", ->
|
||||
describe "when the nvatom:toggle event is triggered", ->
|
||||
it "attaches and then detaches the view", ->
|
||||
expect(atom.workspaceView.find('.notational-velocity')).not.toExist()
|
||||
expect(workspaceElement.querySelector('.nvatom')).not.toExist()
|
||||
|
||||
# This is an activation event, triggering it will cause the package to be
|
||||
# activated.
|
||||
atom.commands.dispatch atom.workspaceView.element, 'notational-velocity:toggle'
|
||||
# This is an activation event, triggering it will cause the package to be activated.
|
||||
atom.commands.dispatch workspaceElement, 'nvatom:toggle'
|
||||
|
||||
waitsForPromise ->
|
||||
activationPromise
|
||||
|
||||
runs ->
|
||||
expect(atom.workspaceView.find('.notational-velocity')).toExist()
|
||||
atom.commands.dispatch atom.workspaceView.element, 'notational-velocity:toggle'
|
||||
expect(workspaceElement.querySelector('.nvatom')).toExist()
|
||||
atom.commands.dispatch workspaceElement, 'nvatom:toggle'
|
||||
|
||||
it "checks if we banned the default directory under packages directory", ->
|
||||
atom.notifications.clear()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('notifications')
|
||||
|
||||
runs ->
|
||||
noteDirectoryUnderPackageDirectory = path.join(process.env.ATOM_HOME, 'packages', 'nvatom', 'notebook')
|
||||
atom.config.set('nvatom.directory', noteDirectoryUnderPackageDirectory)
|
||||
|
||||
# This is an activation event, triggering it will cause the package to be activated.
|
||||
atom.commands.dispatch workspaceElement, 'nvatom:toggle'
|
||||
|
||||
waitsForPromise ->
|
||||
activationPromise
|
||||
|
||||
runs ->
|
||||
notificationContainer = workspaceElement.querySelector('atom-notifications')
|
||||
notification = notificationContainer.querySelector('atom-notification.fatal')
|
||||
expect(notification).toExist()
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
NotationalVelocityView = require '../lib/notational-velocity-view'
|
||||
|
||||
describe "NotationalVelocityView", ->
|
||||
it "has one valid test", ->
|
||||
expect("life").toBe "life"
|
||||
@@ -1,117 +0,0 @@
|
||||
path = require 'path'
|
||||
fs = require 'fs-plus'
|
||||
temp = require 'temp'
|
||||
pathWatcher = require 'pathwatcher'
|
||||
NoteDirectory = require '../lib/note-directory'
|
||||
Note = require '../lib/note'
|
||||
|
||||
describe 'NoteDirectory.getNotes', ->
|
||||
defaultDirectory = atom.config.get('notational-velocity.directory')
|
||||
tempDirectory = temp.mkdirSync('node-pathwatcher-directory')
|
||||
noteDirectory = null
|
||||
isCallbackCalled = false
|
||||
|
||||
# We don't want to let the mtimes of two consecutively create files are same.
|
||||
# This function ensures the mtime of the file created before calling this function to be always
|
||||
# smaller than to the mtime of the file created after calling this function.
|
||||
wait = ->
|
||||
timestampDirectory = temp.mkdirSync('node-pathwatcher-timestamp')
|
||||
filePath = path.join(timestampDirectory, 'temp')
|
||||
fs.writeFileSync(filePath, '.')
|
||||
mtimeOld = fs.statSync(filePath).mtime
|
||||
mtimeNew = mtimeOld
|
||||
while mtimeOld >= mtimeNew
|
||||
fs.writeFileSync(filePath, '.')
|
||||
mtimeNew = fs.statSync(filePath).mtime
|
||||
|
||||
beforeEach ->
|
||||
isCallbackCalled = false
|
||||
callback = => isCallbackCalled = true
|
||||
|
||||
atom.config.set('notational-velocity.directory', tempDirectory)
|
||||
|
||||
fs.writeFileSync(path.join(tempDirectory, 'Readme.md'), 'read me')
|
||||
wait()
|
||||
|
||||
fs.mkdirSync(path.join(tempDirectory, 'Car'))
|
||||
fs.writeFileSync(path.join(tempDirectory, 'Car', 'Mini.md'), 'mini')
|
||||
wait()
|
||||
|
||||
noteDirectory = new NoteDirectory(tempDirectory, null, callback)
|
||||
|
||||
afterEach ->
|
||||
noteDirectory.destroy()
|
||||
fs.unlinkSync(path.join(tempDirectory, 'Car', 'Mini.md'))
|
||||
fs.rmdirSync(path.join(tempDirectory, 'Car'))
|
||||
fs.unlinkSync(path.join(tempDirectory, 'Readme.md'))
|
||||
atom.config.set('notational-velocity.directory', defaultDirectory)
|
||||
|
||||
it 'gives a list of notes in the order so that the newest one comes first', ->
|
||||
notes = noteDirectory.getNotes()
|
||||
expect(notes.length).toEqual(2)
|
||||
expect(notes[0].getText()).toBe 'mini'
|
||||
expect(notes[1].getText()).toBe 'read me'
|
||||
expect(notes[0].getModified().getTime()).toBeGreaterThan(notes[1].getModified().getTime())
|
||||
|
||||
it 'changes its order when a note is changed', ->
|
||||
fs.writeFileSync(path.join(tempDirectory, 'Readme.md'), 'read me new')
|
||||
wait()
|
||||
|
||||
waitsFor -> isCallbackCalled
|
||||
runs ->
|
||||
notes = noteDirectory.getNotes()
|
||||
expect(notes[0].getText()).toBe 'read me new'
|
||||
expect(notes[1].getText()).toBe 'mini'
|
||||
|
||||
it 'changes its order when a note is created', ->
|
||||
fs.writeFileSync(path.join(tempDirectory, 'Car', 'Prius.md'), 'prius')
|
||||
wait()
|
||||
|
||||
waitsFor -> isCallbackCalled
|
||||
runs ->
|
||||
notes = noteDirectory.getNotes()
|
||||
expect(notes.length).toEqual(3)
|
||||
expect(notes[0].getText()).toBe 'prius'
|
||||
expect(notes[1].getText()).toBe 'mini'
|
||||
expect(notes[2].getText()).toBe 'read me'
|
||||
fs.unlinkSync(path.join(tempDirectory, 'Car', 'Prius.md'))
|
||||
|
||||
it 'changes its order when a note is deleted', ->
|
||||
fs.unlinkSync(path.join(tempDirectory, 'Car', 'Mini.md'))
|
||||
wait()
|
||||
|
||||
waitsFor -> isCallbackCalled
|
||||
runs ->
|
||||
notes = noteDirectory.getNotes()
|
||||
expect(notes.length).toEqual(1)
|
||||
expect(notes[0].getText()).toBe 'read me'
|
||||
# So that it won't spit an error in the teardown stage.
|
||||
fs.writeFileSync(path.join(tempDirectory, 'Car', 'Mini.md'), 'mini')
|
||||
|
||||
it 'changes its order when a note is renamed', ->
|
||||
oldPath = path.join(tempDirectory, 'Car', 'Mini.md')
|
||||
newPath = path.join(tempDirectory, 'Mini.md')
|
||||
fs.renameSync(oldPath, newPath)
|
||||
wait()
|
||||
|
||||
waitsFor -> isCallbackCalled
|
||||
runs ->
|
||||
notes = noteDirectory.getNotes()
|
||||
expect(notes.length).toEqual(2)
|
||||
expect(notes[0].getTitle()).toBe 'Mini'
|
||||
expect(notes[1].getTitle()).toBe 'Readme'
|
||||
# So that it won't spit an error in the teardown stage.
|
||||
fs.renameSync(newPath, oldPath)
|
||||
|
||||
it 'updates properly when a directory is created and a note is created inside it', ->
|
||||
fs.mkdirSync(path.join(tempDirectory, 'Food'))
|
||||
fs.writeFileSync(path.join(tempDirectory, 'Food', 'Milk.md'), 'milk')
|
||||
wait()
|
||||
waitsFor -> isCallbackCalled
|
||||
runs ->
|
||||
notes = noteDirectory.getNotes()
|
||||
expect(notes.length).toEqual(3)
|
||||
expect(notes[0].getText()).toBe 'milk'
|
||||
# So that it won't spit an error in the teardown stage.
|
||||
fs.unlinkSync(path.join(tempDirectory, 'Food', 'Milk.md'))
|
||||
fs.rmdirSync(path.join(tempDirectory, 'Food'))
|
||||
@@ -1,36 +0,0 @@
|
||||
path = require 'path'
|
||||
fs = require 'fs-plus'
|
||||
temp = require 'temp'
|
||||
pathWatcher = require 'pathwatcher'
|
||||
Note = require '../lib/note'
|
||||
|
||||
describe 'Note', ->
|
||||
defaultDirectory = atom.config.get('notational-velocity.directory')
|
||||
tempDirectory = temp.mkdirSync('node-pathwatcher-directory')
|
||||
tempFilePath = path.join(tempDirectory, 'Temp.md')
|
||||
|
||||
beforeEach ->
|
||||
atom.config.set('notational-velocity.directory', tempDirectory)
|
||||
fs.writeFileSync(tempFilePath, 'old')
|
||||
|
||||
afterEach ->
|
||||
fs.unlinkSync(tempFilePath)
|
||||
atom.config.set('notational-velocity.directory', defaultDirectory)
|
||||
|
||||
it 'creates a note', ->
|
||||
note = new Note(tempFilePath, null, null)
|
||||
expect(note.getTitle()).toBe 'Temp'
|
||||
expect(note.getText()).toBe 'old'
|
||||
expect(note.getFilePath()).toBe tempFilePath
|
||||
note.destroy()
|
||||
|
||||
it 'modifies a note', ->
|
||||
note = new Note(tempFilePath, null, null)
|
||||
expect(note.getText()).toBe 'old'
|
||||
|
||||
fs.writeFileSync(tempFilePath, 'new')
|
||||
oldModified = note.getModified()
|
||||
waitsFor -> oldModified != note.getModified()
|
||||
runs ->
|
||||
expect(note.getText()).toBe 'new'
|
||||
note.destroy()
|
||||
@@ -4,7 +4,7 @@
|
||||
// for a full listing of what's available.
|
||||
@import "ui-variables";
|
||||
|
||||
.notational-velocity {
|
||||
.nvatom {
|
||||
li {
|
||||
text-overflow: ellipsis;
|
||||
overflow-x: hidden;
|
||||
|
||||
Reference in New Issue
Block a user