├── .eslintrc.json
├── .github
└── FUNDING.yml
├── .gitignore
├── .vscode
├── extensions.json
├── launch.json
├── settings.json
└── tasks.json
├── .vscodeignore
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── docs
├── codeactions.gif
├── codeactions.md
├── commands.md
├── complete.gif
├── entries.gif
├── entries.md
├── img
│ ├── date.png
│ ├── offset.png
│ ├── shortcut.png
│ ├── smartinput.png
│ └── weekday.png
├── into.gif
├── intro.gif
├── known_issues.md
├── memo.md
├── memos.gif
├── momentjs_duration.gif
├── momentjs_duration2.gif
├── navigation.gif
├── notes.gif
├── notes.md
├── print.md
├── printCommands.gif
├── scopes.gif
├── scopes.md
├── set-base-directory.gif
├── settings.md
├── smartInput.md
├── tasks.gif
└── tasks.md
├── img
├── logo.png
├── logo.svg
└── time.gif
├── package-lock.json
├── package.json
├── res
├── colors
│ ├── dark.json
│ └── light.json
├── snippets
│ └── markdown.json
└── syntax
│ └── journal-markdown.json
├── src
├── actions
│ ├── index.ts
│ ├── inject.d.ts
│ ├── inject.ts
│ ├── parser.d.ts
│ ├── parser.ts
│ ├── reader.d.ts
│ ├── reader.ts
│ ├── writer.d.ts
│ └── writer.ts
├── ext
│ ├── commands.d.ts
│ ├── conf.d.ts
│ ├── conf.ts
│ ├── dialogues.ts
│ ├── index.d.ts
│ ├── index.ts
│ ├── messages.json
│ ├── startup.d.ts
│ ├── startup.ts
│ ├── translations.ts
│ ├── vscode-codelens.ts
│ └── vscode.d.ts
├── extension.d.ts
├── extension.ts
├── index.d.ts
├── index.ts
├── model
│ ├── config.ts
│ ├── files.ts
│ ├── index.ts
│ ├── inline.ts
│ ├── input.d.ts
│ ├── input.ts
│ ├── templates.ts
│ └── vscode.ts
├── provider
│ ├── InputMatcher.d.ts
│ ├── codeactions
│ │ ├── for-completed-tasks.ts
│ │ └── for-open-tasks.ts
│ ├── codelens
│ │ ├── migrate-tasks.ts
│ │ └── shift-task.ts
│ ├── commands
│ │ ├── copy-task.ts
│ │ ├── index.ts
│ │ ├── insert-memo.ts
│ │ ├── open-journal-workspace.ts
│ │ ├── print-current-time.ts
│ │ ├── print-duration-between-selected-times.ts
│ │ ├── print-sum-of-selected-numbers.ts
│ │ ├── show-entry-for-date.ts
│ │ ├── show-entry-for-input.ts
│ │ ├── show-entry-for-today.ts
│ │ ├── show-entry-for-tomorrow.ts
│ │ ├── show-entry-for-yesterday.ts
│ │ └── show-note.ts
│ ├── features
│ │ ├── load-note.ts
│ │ ├── match-input.ts
│ │ ├── scan-entries.ts
│ │ ├── show-pick-list.ts
│ │ └── sync-note-links.ts
│ ├── index.d.ts
│ └── index.ts
├── test
│ ├── Readme.md
│ ├── TestLogger.d.ts
│ ├── TestLogger.ts
│ ├── direct
│ │ ├── direct.d.ts
│ │ ├── direct.ts
│ │ ├── input_parser.d.ts
│ │ ├── input_parser.ts
│ │ ├── path-parse-with-date.ts
│ │ ├── replace-variables-in-string.ts
│ │ └── simple-run-command.ts
│ ├── runTest.d.ts
│ ├── runTest.ts
│ └── suite
│ │ ├── extension.test.d.ts
│ │ ├── index.d.ts
│ │ ├── index.ts
│ │ ├── input.test.ts
│ │ ├── notes_sync.test.ts
│ │ ├── read_templates.test.ts
│ │ └── week_input.test.ts
└── util
│ ├── controller.ts
│ ├── dates.ts
│ ├── index.d.ts
│ ├── index.ts
│ ├── logger.d.ts
│ ├── logger.ts
│ ├── paths.ts
│ ├── startup.d.ts
│ ├── strings.ts
│ ├── util.d.ts
│ └── util.ts
├── test
├── Readme.md
├── backup
│ └── user-settings.cjson
├── ws_manual
│ └── .gitignore
└── ws_unittests
│ └── .gitignore
├── tsconfig.json
└── webpack.config.js
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "parser": "@typescript-eslint/parser",
4 | "parserOptions": {
5 | "ecmaVersion": 6,
6 | "sourceType": "module"
7 | },
8 | "plugins": [
9 | "@typescript-eslint"
10 | ],
11 | "rules": {
12 | "@typescript-eslint/naming-convention": "warn",
13 | "@typescript-eslint/semi": "warn",
14 | "curly": "warn",
15 | "eqeqeq": "warn",
16 | "no-throw-literal": "warn",
17 | "semi": "off"
18 | },
19 | "ignorePatterns": [
20 | "out",
21 | "dist",
22 | "**/*.d.ts"
23 | ]
24 | }
25 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: pajoma
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | out
2 | dist
3 | node_modules
4 | *.vsix
5 | npm-debug*
6 | src/*.js
7 | *.js.map
8 |
9 | *.log
10 | *.old
11 | test/workspace
12 | test/test
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // See http://go.microsoft.com/fwlink/?LinkId=827846
3 | // for the documentation about the extensions.json format
4 | "recommendations": [
5 | "dbaeumer.vscode-eslint",
6 | "eamodio.tsl-problem-matcher"
7 | ]
8 | }
9 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | // A launch configuration that compiles the extension and then opens it inside a new window
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | {
6 | "version": "0.2.0",
7 | "configurations": [
8 | {
9 | "name": "Run Extension",
10 | "type": "extensionHost",
11 | "request": "launch",
12 | "args": [
13 | "--extensionDevelopmentPath=${workspaceFolder}",
14 | "${workspaceFolder}/test/ws_manual/"
15 | ],
16 | "outFiles": [
17 | "${workspaceFolder}/dist/**/*.js"
18 | ],
19 | "preLaunchTask": "${defaultBuildTask}"
20 | },
21 | {
22 | "name": "Run Extension without Workspace",
23 | "type": "extensionHost",
24 | "request": "launch",
25 | "args": [
26 | "--extensionDevelopmentPath=${workspaceFolder}",
27 | "${workspaceFolder}/test/ws_empty/"
28 | ],
29 | "outFiles": [
30 | "${workspaceFolder}/dist/**/*.js"
31 | ],
32 | "preLaunchTask": "${defaultBuildTask}"
33 | },
34 | {
35 | "name": "Extension Tests",
36 | "type": "extensionHost",
37 | "request": "launch",
38 | "args": [
39 | "--extensionDevelopmentPath=${workspaceFolder}",
40 | "--extensionTestsPath=${workspaceFolder}/out/test/suite/index",
41 | "${workspaceFolder}/test/ws_unittests/"
42 | ],
43 | "outFiles": [
44 | "${workspaceFolder}/out/**/*.js",
45 | "${workspaceFolder}/dist/**/*.js"
46 | ],
47 | "preLaunchTask": "tasks: watch-tests"
48 | }
49 | ]
50 | }
51 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | // Place your settings in this file to overwrite default and user settings.
2 | {
3 | "files.exclude": {
4 | "out": false, // set this to true to hide the "out" folder with the compiled JS files
5 | "dist": false, // set this to true to hide the "dist" folder with the compiled JS files
6 | "src/**/*.js": false,
7 | "**/*.d.ts": true,
8 | "**/*.js.map": true
9 | },
10 | "search.exclude": {
11 | "out": true, // set this to false to include "out" folder in search results
12 | "dist": true // set this to false to include "dist" folder in search results
13 | },
14 | // Turn off tsc task auto detection since we have the necessary tasks as npm scripts
15 | "typescript.tsc.autoDetect": "off"
16 | }
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | // See https://go.microsoft.com/fwlink/?LinkId=733558
2 | // for the documentation about the tasks.json format
3 | {
4 | "version": "2.0.0",
5 | "tasks": [
6 | {
7 | "type": "npm",
8 | "script": "watch",
9 | "problemMatcher": [
10 | "$ts-webpack-watch",
11 | "$tslint-webpack-watch"
12 | ],
13 | "isBackground": true,
14 | "presentation": {
15 | "reveal": "never",
16 | "group": "watchers"
17 | },
18 | "group": {
19 | "kind": "build",
20 | "isDefault": true
21 | }
22 | },
23 | {
24 | "type": "npm",
25 | "script": "watch-tests",
26 | "problemMatcher": "$tsc-watch",
27 | "isBackground": true,
28 | "presentation": {
29 | "reveal": "never",
30 | "group": "watchers"
31 | },
32 | "group": "build"
33 | },
34 | {
35 | "label": "tasks: watch-tests",
36 | "dependsOn": [
37 | "npm: watch",
38 | "npm: watch-tests"
39 | ],
40 | "problemMatcher": []
41 | },
42 | {
43 | "type": "npm",
44 | "script": "compile-tests",
45 | "group": "build",
46 | "problemMatcher": [],
47 | "label": "npm: compile-tests",
48 | "detail": "tsc -p . --outDir out"
49 | }
50 | ]
51 | }
--------------------------------------------------------------------------------
/.vscodeignore:
--------------------------------------------------------------------------------
1 | .vscode/**
2 | .vscode-test/**
3 | out/**
4 | node_modules/**
5 | src/**
6 | .gitignore
7 | .yarnrc
8 | webpack.config.js
9 | vsc-extension-quickstart.md
10 | **/tsconfig.json
11 | **/.eslintrc.json
12 | **/*.map
13 | **/*.ts
14 | test/**
15 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to VSCode-Journal
2 | Thank you so much for your interest in contributing! All types of contributions are encouraged and valued.
3 |
4 | ## About the Project
5 | I have been writing notes every day for over 10 years and still use this extension all the time. In the beginning only with Notepad and other text editors. When the first version of Visual Studio Code came out, I saw an opportunity to get to know Typescript better and started developing this extension. That's why I mainly focus on ideas and extensions that help me in my daily work.
6 |
7 | The source code reflects this journey. A bit bumpy at the beginning (and still today for sure, all this javascript stuff makes me doubt myself often enough), but it got a bit better with the years.
8 |
9 | ## How to contribute
10 |
11 | There are several ways to contribute.
12 |
13 | * If you find any issues, weird behaviour or plain error, don't hesitate to [open an issue](https://github.com/pajoma/vscode-journal/issues/new). I try to react timely, but don't count on it.
14 | * [Start a discussion](https://github.com/pajoma/vscode-journal/discussions/new) if you have question or feature requests. Or see if there are any other unanswered questions you might be able to answer.
15 | * Leave a review on the [marketplace](https://marketplace.visualstudio.com/items?itemName=pajoma.vscode-journal&ssr=false#review-details) and keep me motivated ;)
16 | * Let me buy a beer by [sponsoring](https://github.com/sponsors/pajoma) my work here
17 |
18 | If you plan to contribute with updates to the source, follow these steps
19 |
20 | * Outline your idea in the discussions.
21 | * Talk to me on [Gitter](https://gitter.im/dictyo) for further questions.
22 | * Create a fork, do your thing, and create a pull request. Please write tests if possible.
23 |
24 | ## Code of conduct
25 |
26 | Just be decent.
27 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 | 
3 | 
4 | 
5 | 
6 |
7 |
8 |
9 |
10 |
11 | |
12 |
13 |
14 | vscode-journal
15 |
16 | Lightweight Extension for Visual Studio Code to take track of your daily notes.
17 | |
18 |
19 |
20 |
21 |
22 |
23 |
24 | ## What is this extension about?
25 | This extension is useful for people like me, who use simple text files for notes, task lists, and everything else which has to be remembered and searched for. Text (or Markdown) in files is easy to backup, sync and can be opened anywhere by everything. This extension has the following functions:
26 |
27 | * Open or create a journal entries for a specific day ([details and videos](./docs/entries.md))
28 | * Add detailed notes for today ([details and videos](./docs/notes.md))
29 | * Add a memo to today's journal page ([details and videos](./docs/memo.md))
30 | * Manage your tasks ([details and videos](./docs/tasks.md))
31 | * Print commands and snippets to support various tasks ([details and videos](./docs/print.md))
32 | * Configure scopes to manage notes of different projects ([details](./docs/scopes.md))
33 | * Use code actions to work on your task lists ([details](./docs/codeactions.md))
34 |
35 | ## Features
36 | Press `Ctrl+Shift+J` to open the journal's smart input and start typing right away. Press `F1` or `Ctrl+Shift+P` to access one of the commands. All supported commands are described [here](./docs/commands.md).
37 |
38 | The notes are stored in a folder on your desktop using the following structure (taking ZIM Desktop wiki as inspiration: `year/month/day.md`, the notes files for October 22th would be `../2016/10/22.md`. Detailed notes (e.g. meeting notes) are placed in the subfolder `../2016/10/22/some-meeting-notes.md`.
39 |
40 | ## Contributing
41 | I am always looking for feedback, new ideas and your help. Check the [contribution guidelines](./CONTRIBUTING.md)
42 |
43 | ## Suggested extensions
44 | vscode-journal is mainly responsible for organizing your notes and journal entries, it does not come with any user interface (besides the smart input). If you prefer tree like views for your notes and tasks, have a look at the following extensions by Gruntfuggly and Kortina
45 |
46 | * [vscode-journal-view](https://marketplace.visualstudio.com/items?itemName=Gruntfuggly.vscode-journal-view) to easly navigate to your entries and notes by date
47 | * [todo-tree](https://marketplace.visualstudio.com/items?itemName=Gruntfuggly.todo-tree) to quickly access and manage your tasks
48 | * [markdown notes](https://marketplace.visualstudio.com/items?itemName=kortina.vscode-markdown-notes) for enhanced navigation capabilities between your notes
49 |
50 |
51 | ## Settings
52 | Settings are described in detail [here](./docs/settings.md)
53 |
54 | You have to set the base folder for notes folder structure before you start. Open your settings, search for 'journal' and copy the journal.base line into your personal settings. Adjust the value, for example: ` "journal.base": "C:/Users/FooBar/Documents/Journal"` (use forward slash!)
55 |
56 | The default file format is Markdown (using `md` as extension), which is natively supported by Visual Studio Code. I use Asciidoc for my notes (with `.adoc` as extension), in this case you should also install an Asciidoc Syntax extension.
57 |
58 | Syntax highlighting is configured in your workspace settings. The options are stored automatically in the settings, you can then manually change them. Make sure to restart to apply the changes. The settings try to recognize if a dark or light theme is used. If you switch in between, you either have to delete the settings (to reload them from the extension) or adapt them for yourself.
59 |
60 |
61 | ## Demo
62 |
63 | 
--------------------------------------------------------------------------------
/docs/codeactions.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pajoma/vscode-journal/34ca1290d759c7c32caca9858d78235aae0ea423/docs/codeactions.gif
--------------------------------------------------------------------------------
/docs/codeactions.md:
--------------------------------------------------------------------------------
1 | # Code Actions
2 |
3 | Code actions are a Visual Studio Code feature (and basically every serious other IDE) to quickly run a commands from within the text. For now, the journal extension has code extension active for tasks. When you place your mouse cursor on a line with a task (any line starting with `- []` or `-[x]`), a yellow balloon will appear. You can trigger the selection of code actions by selecting the balloon or using the shortcut `CTRL+.`
4 |
5 | The following actions are supported for now
6 | * Complete a task (marks the task and adds the completion time)
7 | * Reopen a task
8 | * Migrate a task to today (when current entry is from another day). It will modify the task to `[>]` (inspired by bullet journaling) and append the new date
9 | * Migrate a task to tomorrow
10 | * Migrate a task to the next working day (if tomorrow is in the weekend)
11 |
12 |
13 | 
14 |
--------------------------------------------------------------------------------
/docs/commands.md:
--------------------------------------------------------------------------------
1 | # Visual Studio Code Commands of vscode-journal
2 | Press 'F1' or Ctrl+Shift+P to access one of the commands.
3 |
4 | You can access all functionality (besides opening the journal) from the smart input.
5 |
6 | ## Journal Pages
7 |
8 | * `journal:day` (keybindings: `ctrl+shift+j` or `cmd+shift+j` on mac) opens the smart input, see
9 | * `journal:today` for opening today's entry
10 | * `journal:tomorrow`
11 |
12 | ## Notes & Memos
13 | `journal:note` opens a dialog to enter the title of a new page for notes.
14 |
15 | ## Open the journal
16 | `journal:open` starts a new instance of vscode with the base directory of your journal as root
--------------------------------------------------------------------------------
/docs/complete.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pajoma/vscode-journal/34ca1290d759c7c32caca9858d78235aae0ea423/docs/complete.gif
--------------------------------------------------------------------------------
/docs/entries.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pajoma/vscode-journal/34ca1290d759c7c32caca9858d78235aae0ea423/docs/entries.gif
--------------------------------------------------------------------------------
/docs/entries.md:
--------------------------------------------------------------------------------
1 | # Navigating to journal entries
2 |
3 | A journal entry is created for every day. It collects the day's tasks, memos and any other content which you don't want to have in separate notes. I use it personally mostly for time tracking.
4 |
5 | A wide range of different inputs is supported, see [this page](./smartInput.md) for more details.
6 |
7 | 
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/docs/img/date.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pajoma/vscode-journal/34ca1290d759c7c32caca9858d78235aae0ea423/docs/img/date.png
--------------------------------------------------------------------------------
/docs/img/offset.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pajoma/vscode-journal/34ca1290d759c7c32caca9858d78235aae0ea423/docs/img/offset.png
--------------------------------------------------------------------------------
/docs/img/shortcut.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pajoma/vscode-journal/34ca1290d759c7c32caca9858d78235aae0ea423/docs/img/shortcut.png
--------------------------------------------------------------------------------
/docs/img/smartinput.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pajoma/vscode-journal/34ca1290d759c7c32caca9858d78235aae0ea423/docs/img/smartinput.png
--------------------------------------------------------------------------------
/docs/img/weekday.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pajoma/vscode-journal/34ca1290d759c7c32caca9858d78235aae0ea423/docs/img/weekday.png
--------------------------------------------------------------------------------
/docs/into.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pajoma/vscode-journal/34ca1290d759c7c32caca9858d78235aae0ea423/docs/into.gif
--------------------------------------------------------------------------------
/docs/intro.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pajoma/vscode-journal/34ca1290d759c7c32caca9858d78235aae0ea423/docs/intro.gif
--------------------------------------------------------------------------------
/docs/known_issues.md:
--------------------------------------------------------------------------------
1 | # Known Issues
2 |
3 | The following list consists of open issues which I have identified during testing, but decided to ignore them (for now). These issues are either just not worth the effort or just happening w/in rather weird conditions.
4 |
5 | ## Linebreaks for injected links when last line is empty
6 | Sometimes linebreaks are missing between the links
7 |
8 | ## '\n' in template patterns are required
9 | Since the settings need to be within one line, you have to add linebreaks manually. Alternative would be to store the patterns in separate files, which breaks the user story in vscode to edit settings.
10 |
11 | ## Compute Duration always below 12h
12 | Order doesn't matter, we always substract the smaller from the larger. No order was on purpose, I think its better to just add a "+1" to add day breaks (you can then also add +2)
13 |
14 |
--------------------------------------------------------------------------------
/docs/memo.md:
--------------------------------------------------------------------------------
1 | # Working with memos
2 |
3 | 
4 |
5 | Memos are simple reminders within your journal entries. You add memos through the smart input (Ctrl+Shift+J). Just enter any text, it will be added to your today's entry. By adding date modifiers, you can control in which journal entry the memo is inserted.
6 |
7 | * `+1 I have to remember this` adds a memo to tomorrow's journal entry
8 | * `Check out Tom's presentation` adds a memo to today's journal entry
9 | * `Next wednesday call my bank` adds the memo "Call my bank" to next wednesday's journal entry
10 |
11 |
--------------------------------------------------------------------------------
/docs/memos.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pajoma/vscode-journal/34ca1290d759c7c32caca9858d78235aae0ea423/docs/memos.gif
--------------------------------------------------------------------------------
/docs/momentjs_duration.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pajoma/vscode-journal/34ca1290d759c7c32caca9858d78235aae0ea423/docs/momentjs_duration.gif
--------------------------------------------------------------------------------
/docs/momentjs_duration2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pajoma/vscode-journal/34ca1290d759c7c32caca9858d78235aae0ea423/docs/momentjs_duration2.gif
--------------------------------------------------------------------------------
/docs/navigation.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pajoma/vscode-journal/34ca1290d759c7c32caca9858d78235aae0ea423/docs/navigation.gif
--------------------------------------------------------------------------------
/docs/notes.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pajoma/vscode-journal/34ca1290d759c7c32caca9858d78235aae0ea423/docs/notes.gif
--------------------------------------------------------------------------------
/docs/notes.md:
--------------------------------------------------------------------------------
1 | # Working with notes
2 |
3 | 
4 |
5 | Notes are single markdown files linked to the today's journal entry. `journal:note` (in the command palette using the shortcut `Ctrl+Shift+P`) opens a dialog to enter the title of a new page for notes. The title is also the filename (stored typically as subfolder in the journal structure, e.g. folder ´25´ in folder ´10´ if today is 10/25). Local links are automatically added to the current day's journal entry.
6 |
7 | (soon) You can also use the journal's smart input to create a note. Press `Ctrl+Shift+J` and prefix your text with the flag `note`. It will then create a new page using the remaining text in the input as title.
8 |
9 | Notes are automatically linked in the according journal entry (of the same day, when the note has been created).
10 |
11 | ## Support for Scopes
12 | You can add free tags the beginning the
13 |
14 |
15 | If you enter something like "#projectA Workshop Minutes" as title, the new document will be stored not within in the base directory configured for this scope.
16 |
--------------------------------------------------------------------------------
/docs/print.md:
--------------------------------------------------------------------------------
1 | # Working with print commands and snippets
2 |
3 | 
4 |
5 | I use the journal daily to track my time spent on various projects. You can use the following commands (and shortcuts) to compute the duration between two timestamps or to print the sum of various numbers.
6 |
7 | * `Print Time` to enter timestamps at cursor position.
8 | * `Print elapased hours`, which computes the duration between two seleced timestamps (same format as what "Insert time" prints). Shortcut: `Ctrl+J Ctrl+D`
9 | * `Print sum of selected numbers`, which summarizes all selected numbers (I use it to compute the total time). Shortcut: `Ctrl+J Ctrl+S`v
--------------------------------------------------------------------------------
/docs/printCommands.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pajoma/vscode-journal/34ca1290d759c7c32caca9858d78235aae0ea423/docs/printCommands.gif
--------------------------------------------------------------------------------
/docs/scopes.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pajoma/vscode-journal/34ca1290d759c7c32caca9858d78235aae0ea423/docs/scopes.gif
--------------------------------------------------------------------------------
/docs/scopes.md:
--------------------------------------------------------------------------------
1 | # Scopes
2 |
3 | Scopes help you to manage notes within your different projects by declaring individual configurations. Scopes are specific tags such as "#clientA" or "#private". When creating a new note and using that tag in the input box, you tell the extension to use the scope's configuration (and not the global configuration of the journal).
4 |
5 | ## Setting up a new scope
6 | Let's stick to the example of the new scope "#clientA", which you plan to use to store all notes in a new project coming up with a Client.
7 |
8 | ### Configure Settings
9 | Open your settings and adapt ```journal.scopes``` directly in settings.json.
10 |
11 | Visual Studio Code will generate the following snippet for you:
12 |
13 | ```json
14 | "journal.scopes": {
15 | }
16 |
17 | ```
18 | You have to replace the curly brackets with ```[]```, since we expect an array here (a list of scopes).
19 |
20 | Within a scopes definition, you can reconfigure the base path and the file patterns (only notes so far, see below). The following example sets up new scopes for "clientA" and "private". The Notes-Folder for ClientA points to a Git Repository shared with my Team, while the private Folder is part of my normal base path (but notes are not stored under the journal entries).
21 |
22 |
23 | ```json
24 | "journal.scopes": [
25 |
26 | {
27 | "name": "clientA",
28 | "patterns": {
29 | "base": "D:/Repositories/ClientA/SharedNotes",
30 | "notes": {
31 | "path": "${base}/userX",
32 | "file": "${d: YYYYY-DD-MM}-${input}.${ext}"
33 | },
34 | }
35 | },
36 | {
37 | "name": "private",
38 | "patterns": {
39 | "notes": {
40 | "path": "${base}/scopes/private",
41 | "file": "${localDate}-${input}.${ext}"
42 | },
43 | }
44 | }
45 | ]
46 | ```
47 |
48 |
49 | ### Scoped Journal Entries
50 | Supporting scopes for journal entries messes with the input box and would require some serious rewriting of the pattern matching code. Please open an issue if you want this feature.
51 |
52 |
53 | ## Using scopes
54 |
55 | Whenever you want to create a new note, just prefix the note's title with the scope, written as tag.
56 |
57 | 1. Press ```Ctrl+Shift+J```
58 | 2. Pick "Select or create note"
59 | 3. Enter the scope and some text, for example ```#clientA Sprint Daily Notes```
60 |
61 | The details for the highlighted item in picklist should tell you, if the scope has been detected and should look like
62 | ```Create new note in scope #clientA and tags #clientA```. Any other tags you enter here will be pasted in the new file.
63 |
64 | 
65 |
--------------------------------------------------------------------------------
/docs/set-base-directory.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pajoma/vscode-journal/34ca1290d759c7c32caca9858d78235aae0ea423/docs/set-base-directory.gif
--------------------------------------------------------------------------------
/docs/smartInput.md:
--------------------------------------------------------------------------------
1 | # Examples how to use the smart input
2 |
3 | Using the shortcut ```CTRL+SHIFT+J``` to opens the following dialog.
4 |
5 | 
6 |
7 | From there you can either start typing away (see below for options) or select one of the following options:
8 |
9 | * *Today* selects or creates the journal entry of the today
10 | * *Tomorrow* selects or creates the journal entry of the tomorrow
11 | * *Select entry* opens a list of existing journal entries
12 | * *Select/Create a note* opens a list of existing notes for selection. You are still able to create a new note by simply typing the note title.
13 |
14 | This guide including its examples assume english as your display language. If you changed the setting **Display Language** in Visual Studio Code, you probably see other messages. Supported languages for this extension are:
15 |
16 | * English (en)
17 | * German (de)
18 | * French (fr)
19 | * Spanish (es)
20 | * Italian (it)
21 | * Portuguese (pt)
22 | * Dutch (nl)
23 | * Russian (ru)
24 | * Chinese (Pinyin) (zh)
25 | * Japanese (Romaji) (ja)
26 | * Arabic (ar)
27 |
28 |
29 | ## Supported input options
30 | The help text in the dialog will tell you, what action will be performed after analyzing the input.
31 |
32 | The following actions are possible:
33 | * Pick a specific journal entry by entering a shortcut, offset, weekday or specific date
34 | * Open a week's entry (last, this, and next, or a numbered calendar week)
35 | * Add a memo to today's page or to a page of a specific date
36 | * Add a task to today's page or to a page of a specific date
37 |
38 |
39 |
40 | ### Pick journal entry by shortcut
41 | 
42 |
43 | Supported shortcuts are
44 |
45 | * `today, tod` for today's journal entry
46 | * `tomorrow, tom` for tomorrow's journal entry
47 | * `yesterday, yes` for yesterday's journal entry
48 |
49 | Each entry will also create the entry if it doesn't exist yet.
50 |
51 |
52 | ### Pick journal entry by offset
53 | 
54 |
55 | * ``` 0 ``` to select today's entry. Or simply press enter.
56 | * ``` -1 ``` to select yesterday's entry
57 | * ``` +1 ``` to select tomorrows entry
58 | * ``` -2423 ``` to select a day far in the past
59 |
60 | ### Pick journal entry by day of week
61 | 
62 |
63 | Supported values are `monday, mon, tuesday, tue, wednesday, wed, thursday, thu, friday, fri, saturday, sat, sunday, sun`
64 |
65 | You can use the modifiers `last` and `next` to go either into the past or future. The last is the default, if you simply enter `mon`, the journal page for next monday will be opened.
66 |
67 | * `next wednesday` for journal entry of next wednesday
68 | * `last wednesday` for journal entry of next wednesday
69 |
70 | ### Pick weekly entry
71 | Supported values are `week w13`
72 |
73 | You can use the modifiers `last` and `next` to go either into the past or future. The last is the default, if you simply enter `w` or `week`, the weekly page for the current week is opened
74 |
75 | * `next week` for weekly entry of next calendar week
76 | * `last week` for weekly entry of last calendar week
77 | * `w1` for weekly entry of the first week of this year
78 | * `w99` works as well (well, why not)
79 |
80 |
81 |
82 | ### Pick journal entry by date
83 | 
84 |
85 | You can jump to a specific date using the following options
86 |
87 | * `25`: By only enterying a number, the journal entry for the day of the current month is selected
88 | * `10-25` selects Oct 25 of the current year
89 | * `2015-25-10` for Oct 25 in 2015
90 |
91 | The syntax follows the ISO Standard `YYYY-MM--DD`
92 |
93 |
94 | ### Add a memo to today's page
95 | `This is an important thing to remember`
96 |
97 | Just enter any text. If no modifiers (a date modifier for picking a journal entry) or the flag "task" are included, the new text will added as memo to the journal entry of the current day.
98 |
99 |
100 |
101 | ### Add a memo to any journal entry
102 | `+1 I have to remember this`
103 |
104 | Enter any of the modifiers (offset, date or weekday) _before_ entering any text. The new memo will then be added to the journal page of the selected date.
105 |
106 | ### Add a task to today's page
107 | `todo Order christmas presents`
108 |
109 | If you add flags like `todo` or `task` _before_ any text, it will be added as task to page of the journal entry of the current day.
110 |
111 | Other examples
112 |
113 | * `task fri Submit proposal` if you have a deadline this friday
114 | * `task 10-30 Buy myself a present for my birthday` .. since why not
115 | * `task next wed Remember the milk` .. because the one in the fridge is spoiled by then
116 |
117 |
--------------------------------------------------------------------------------
/docs/tasks.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pajoma/vscode-journal/34ca1290d759c7c32caca9858d78235aae0ea423/docs/tasks.gif
--------------------------------------------------------------------------------
/docs/tasks.md:
--------------------------------------------------------------------------------
1 | # Working with tasks
2 |
3 | 
4 |
5 | Tasks are modelled as checkpoints in your journal entries, e.g.
6 |
7 | ```markdown
8 | # Sunday, 2018/06/03
9 |
10 | - [ ] Task: Fill out my taxes
11 | - [x] Task: Finish the exercise
12 | ```
13 |
14 | You can enter tasks either manually or by the journal smart input (using `Ctrl+Shift+J`). The following examples work for the smart input:
15 |
16 | * `task Fill out my taxes` adds a task to today's entry
17 | * `task 06-24 Call my mom` adds a task for entry of June 24th
18 | * `task +1 Call my mom` adds a task for entry for tomorrow
19 | * `task tom Call my mom` adds a task for entry for tomorrow
20 | * `task next friday Call my mom` adds a task for entry for next friday
21 |
22 |
23 |
--------------------------------------------------------------------------------
/img/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pajoma/vscode-journal/34ca1290d759c7c32caca9858d78235aae0ea423/img/logo.png
--------------------------------------------------------------------------------
/img/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
107 |
--------------------------------------------------------------------------------
/img/time.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pajoma/vscode-journal/34ca1290d759c7c32caca9858d78235aae0ea423/img/time.gif
--------------------------------------------------------------------------------
/res/colors/dark.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "scope": "text.html.markdown.journal.task.open.bullet",
4 | "settings": {
5 | "foreground": "#FFFF00"
6 | }
7 | },
8 | {
9 | "scope": "text.html.markdown.journal.task.open.marker",
10 | "settings": {
11 | "foreground": "#FFFF00"
12 | }
13 | },
14 | {
15 | "scope": "text.html.markdown.journal.task.open.keyword",
16 | "settings": {
17 | "fontStyle": "italic"
18 | }
19 | },
20 | {
21 | "scope": "text.html.markdown.journal.task.open.text",
22 | "settings": {}
23 | },
24 | {
25 | "scope": "text.html.markdown.journal.task.completed.keyword",
26 | "settings": {
27 | "fontStyle": "italic"
28 | }
29 | },
30 | {
31 | "scope": "text.html.markdown.journal.task.completed.marker",
32 | "settings": {
33 | "foreground": "#AAAAAA"
34 | }
35 | },
36 | {
37 | "scope": "text.html.markdown.journal.task.completed.text",
38 | "settings": {
39 | "foreground": "#AAAAAA"
40 | }
41 | },
42 | {
43 | "scope": "text.html.markdown.journal.task.completed.bullet",
44 | "settings": {
45 | "foreground": "#FFFF00"
46 | }
47 | },
48 | {
49 | "scope": "text.html.markdown.journal.memo.keyword",
50 | "settings": {
51 | "fontStyle": "italic"
52 | }
53 | },
54 | {
55 | "scope": "text.html.markdown.journal.memo.bullet",
56 | "settings": {
57 | "foreground": "#FFFF00"
58 | }
59 | },
60 | {
61 | "scope": "text.html.markdown.journal.scope",
62 | "settings": {
63 | "foreground": "#FFFF00"
64 | }
65 | },
66 | {
67 | "scope": "text.html.markdown.journal.link.keyword",
68 | "settings": {
69 | "fontStyle": "italic"
70 | }
71 | },
72 | {
73 | "scope": "text.html.markdown.journal.link.bullet",
74 | "settings": {
75 | "foreground": "#FFFF00"
76 | }
77 | }
78 | ]
--------------------------------------------------------------------------------
/res/colors/light.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "scope": "text.html.markdown.journal.task.open.bullet",
4 | "settings": {
5 | "foreground": "#CC3300"
6 | }
7 | },
8 | {
9 | "scope": "text.html.markdown.journal.task.open.marker",
10 | "settings": {
11 | "foreground": "#CC3300"
12 | }
13 | },
14 | {
15 | "scope": "text.html.markdown.journal.task.open.keyword",
16 | "settings": {
17 | "fontStyle": "italic"
18 | }
19 | },
20 | {
21 | "scope": "text.html.markdown.journal.task.open.text",
22 | "settings": {}
23 | },
24 | {
25 | "scope": "text.html.markdown.journal.task.completed.keyword",
26 | "settings": {
27 | "fontStyle": "italic"
28 | }
29 | },
30 | {
31 | "scope": "text.html.markdown.journal.task.completed.marker",
32 | "settings": {
33 | "foreground": "#AAAAAA"
34 | }
35 | },
36 | {
37 | "scope": "text.html.markdown.journal.task.completed.text",
38 | "settings": {
39 | "foreground": "#AAAAAA"
40 | }
41 | },
42 | {
43 | "scope": "text.html.markdown.journal.task.completed.bullet",
44 | "settings": {
45 | "foreground": "#CC3300"
46 | }
47 | },
48 | {
49 | "scope": "text.html.markdown.journal.memo.keyword",
50 | "settings": {
51 | "fontStyle": "italic"
52 | }
53 | },
54 | {
55 | "scope": "text.html.markdown.journal.memo.bullet",
56 | "settings": {
57 | "foreground": "#CC3300"
58 | }
59 | },
60 | {
61 | "scope": "text.html.markdown.journal.scope",
62 | "settings": {
63 | "foreground": "#CC3300"
64 | }
65 | },
66 | {
67 | "scope": "text.html.markdown.journal.link.keyword",
68 | "settings": {
69 | "fontStyle": "italic"
70 | }
71 | },
72 | {
73 | "scope": "text.html.markdown.journal.link.bullet",
74 | "settings": {
75 | "foreground": "#CC3300"
76 | }
77 | }
78 | ]
--------------------------------------------------------------------------------
/res/snippets/markdown.json:
--------------------------------------------------------------------------------
1 | {
2 | "Create Task": {
3 | "prefix": "task",
4 | "body": [
5 | "- [ ] ${1:description}"
6 | ],
7 | "description": "Snippet for adding a new task"
8 | },
9 | "Track time": {
10 | "prefix": "track",
11 |
12 |
13 | "body": [
14 | "${1:start}-${2:end} | | ${3:tags} | ${4:description}"
15 | ],
16 | "description": "Snippet for tracking time"
17 | }
18 | }
--------------------------------------------------------------------------------
/res/syntax/journal-markdown.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
3 | "fileTypes": [],
4 | "injectionSelector": "L:text.html.markdown",
5 | "patterns": [
6 | {
7 | "include": "#checklist"
8 | },
9 | {
10 | "include": "#scope"
11 | },
12 | {
13 | "include": "#keywords"
14 | }
15 | ],
16 | "repository": {
17 | "scope": {
18 | "patterns": [
19 | {
20 | "match": "(?:\\s|^)(#\\w+)",
21 | "captures": {
22 | "1": {
23 | "name": "text.html.markdown.journal.scope"
24 | }
25 | }
26 | }
27 | ]
28 | },
29 | "checklist": {
30 | "patterns": [
31 | {
32 | "match": "(-|\\*)\\s+(\\[\\s?\\])\\s*(?i:((?:task|todo):?))?\\s(.*)",
33 | "name": "text.html.markdown.journal.task.open",
34 | "captures": {
35 | "1": {
36 | "name": "text.html.markdown.journal.task.open.bullet"
37 | },
38 | "2": {
39 | "name": "text.html.markdown.journal.task.open.marker"
40 | },
41 | "3": {
42 | "name": "text.html.markdown.journal.task.open.keyword"
43 | },
44 | "4": {
45 | "name": "text.html.markdown.journal.task.open.text"
46 | }
47 | }
48 | },
49 | {
50 | "match": "(-|\\*)\\s+(\\[[(?:x|X)\\s?]\\])\\s*(?i:((?:task|todo):?))?\\s(.*)",
51 | "name": "text.html.markdown.journal.task.completed",
52 | "captures": {
53 | "1": {
54 | "name": "text.html.markdown.journal.task.completed.bullet"
55 | },
56 | "2": {
57 | "name": "text.html.markdown.journal.task.completed.marker"
58 | },
59 | "3": {
60 | "name": "text.html.markdown.journal.task.completed.keyword"
61 | },
62 | "4": {
63 | "name": "text.html.markdown.journal.task.completed.text"
64 | }
65 | }
66 | },
67 | {
68 | "match": "(-|\\*)\\s+(\\[[<|>]\\])\\s*(?i:((?:task|todo):?))?\\s(.*)",
69 | "name": "text.html.markdown.journal.task.shifted",
70 | "captures": {
71 | "1": {
72 | "name": "text.html.markdown.journal.task.shifted.bullet"
73 | },
74 | "2": {
75 | "name": "text.html.markdown.journal.task.shifted.marker"
76 | },
77 | "3": {
78 | "name": "text.html.markdown.journal.task.shifted.keyword"
79 | },
80 | "4": {
81 | "name": "text.html.markdown.journal.task.shifted.text"
82 | }
83 | }
84 | },
85 | {
86 | "match": "^(-|\\*)\\s+(?i:((?:memo|link|note):?))",
87 | "name": "text.html.markdown.journal.memo",
88 | "captures": {
89 | "1": {
90 | "name": "text.html.markdown.journal.memo.bullet"
91 | },
92 | "2": {
93 | "name": "text.html.markdown.journal.memo.keyword"
94 | }
95 | }
96 | }
97 | ]
98 | }
99 | },
100 | "scopeName": "text.markdown.journal"
101 | }
--------------------------------------------------------------------------------
/src/actions/index.ts:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2016 Patrick Maué
2 | //
3 | // This file is part of vscode-journal.
4 | //
5 | // vscode-journal is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // vscode-journal is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with vscode-journal. If not, see .
17 | //
18 |
19 |
20 |
21 | export { Parser } from './parser';
22 | export { Writer } from './writer';
23 | export { Reader } from './reader';
24 | export { Inject } from './inject';
25 |
--------------------------------------------------------------------------------
/src/actions/inject.d.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import * as J from '../.';
3 | interface InlineString {
4 | position: vscode.Position;
5 | value: string;
6 | document: vscode.TextDocument;
7 | }
8 | export declare class Inject {
9 | ctrl: J.Util.Ctrl;
10 | constructor(ctrl: J.Util.Ctrl);
11 | /**
12 | * Adds a new memo or task to today's page. A memo/task is a one liner (entered in input box),
13 | * which can be used to quickly write down ToDos without leaving your current
14 | * document.
15 | *
16 | * @param {vscode.TextDocument} doc
17 | * @param {J.Model.Input} input
18 | * @returns {Q.Promise}
19 | * @memberof Inject
20 | */
21 | injectInput(doc: vscode.TextDocument, input: J.Model.Input): Promise;
22 | /**
23 | * Writes content at the location configured in the Inline Template (the "after"-flag). If no after is present,
24 | * content will be injected after the header
25 | *
26 | * @param {vscode.TextDocument} doc
27 | * @param {J.Extension.InlineTemplate} tpl
28 | * @param {...string[][]} values
29 | * @param {number} multiple number of edits which are to be expected (with the same template) to collect and avoid concurrent edits
30 | * @returns {Q.Promise}
31 | * @memberof Inject
32 | *
33 | * Updates: Fix for #55, always make sure there is a linebreak between the header and the injected text to stay markdown compliant
34 | */
35 | private buildInlineString;
36 | /**
37 | * Injects a string into the given position within the given document.
38 | *
39 | * @param doc the vscode document
40 | * @param content the string which is to be injected
41 | * @param position the position where we inject the string
42 | */
43 | injectString(doc: vscode.TextDocument, content: string, position: vscode.Position): Promise;
44 | /**
45 | * Injects the string at the given position.
46 | *
47 | * @param content the @see InlineString to be injected
48 | * @param other additional InlineStrings
49 | *
50 | */
51 | injectInlineString(content: InlineString, ...other: InlineString[]): Promise;
52 | private formatContent;
53 | /**
54 | * Injects the given string as header (first line of file)
55 | *
56 | * @param {vscode.TextDocument} doc the input file
57 | * @param {string} content the string to be injected as header
58 | * @returns {Q.Promise} the updated document
59 | * @memberOf Inject
60 | */
61 | injectHeader(doc: vscode.TextDocument, content: string): Promise;
62 | /**
63 | * Builds the content of newly created notes file using the (scoped) configuration and the user input.
64 | *1
65 | * @param {J.Model.Input} input what the user has entered
66 | * @returns {Q.Promise} the built content
67 | * @memberof Inject
68 | */
69 | formatNote(input: J.Model.Input): Promise;
70 | /**
71 | * Injects a reference to a file associated with the given document. The reference location can be configured in the template (after-flag)
72 | * @param doc the document which we will inject into
73 | * @param file the referenced path
74 | */
75 | private buildReference;
76 | /**
77 | * Checks for the given text document if it contains references to notes (and if there are notes in the associated folders)
78 | * It compares the two lists and creates (or deletes) any missing links
79 | *
80 | * @param doc
81 | */
82 | injectAttachementLinks(doc: vscode.TextDocument, date: Date): Promise;
83 | }
84 | export {};
85 |
--------------------------------------------------------------------------------
/src/actions/parser.d.ts:
--------------------------------------------------------------------------------
1 | import * as J from '../.';
2 | /**
3 | * Helper Methods to interpret the input strings
4 | */
5 | export declare class Parser {
6 | ctrl: J.Util.Ctrl;
7 | today: Date;
8 | private expr;
9 | private scopeExpression;
10 | constructor(ctrl: J.Util.Ctrl);
11 | /**
12 | * Returns the file path for a given input. If the input includes a scope classifier ("#scope"), the path will be altered
13 | * accordingly (depending on the configuration of the scope).
14 | *
15 | * @param {string} input the input entered by the user
16 | * @returns {Q.Promise} the path to the new file
17 | * @memberof JournalCommands
18 | *
19 | */
20 | resolveNotePathForInput(input: J.Model.Input, scopeId?: string): Promise;
21 | /**
22 | * Takes a string and separates the flag, date and text
23 | *
24 | * @param {string} inputString the value to be parsed
25 | * @returns {Promise} the resolved input object
26 | * @memberof Parser
27 | */
28 | parseInput(inputString: string): Promise;
29 | }
30 |
--------------------------------------------------------------------------------
/src/actions/parser.ts:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2022 Patrick Maué
2 | //
3 | // This file is part of vscode-journal.
4 | //
5 | // vscode-journal is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // vscode-journal is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with vscode-journal. If not, see .
17 | //
18 | 'use strict';
19 |
20 | import * as J from '../.';
21 | import * as Path from 'path';
22 |
23 | import { SCOPE_DEFAULT } from '../ext';
24 |
25 | /**
26 | * Helper Methods to interpret the input strings
27 | */
28 | export class Parser {
29 | public today: Date;
30 |
31 | constructor(public ctrl: J.Util.Ctrl) {
32 | this.today = new Date();
33 | }
34 |
35 | /**
36 | * Returns the file path for a given input. If the input includes a scope classifier ("#scope"), the path will be altered
37 | * accordingly (depending on the configuration of the scope).
38 | *
39 | * @param {string} input the input entered by the user
40 | * @returns {Q.Promise} the path to the new file
41 | * @memberof JournalCommands
42 | *
43 | */
44 | public async resolveNotePathForInput(input: J.Model.Input, scopeId?: string): Promise {
45 |
46 |
47 |
48 | return new Promise((resolve, reject) => {
49 | this.ctrl.logger.trace("Entering resolveNotePathForInput() in actions/parser.ts");
50 |
51 | // Unscoped Notes are always created in today's folder
52 | let date = new Date();
53 | let path: string = "";
54 | input.scope = SCOPE_DEFAULT;
55 |
56 | // purge all tags from filename
57 |
58 | // all tags are filtered out. tags representing scopes are recognized here for resolving the note path.
59 | input.text.match(/#\w+\s/g)?.forEach(tag => {
60 | if(J.Util.isNullOrUndefined(tag) || tag!.length === 0) {return;}
61 |
62 | this.ctrl.logger.trace("Tags in input string: "+tag);
63 |
64 | // remove from value
65 | input.tags.push(tag.trim().substring(0, tag.length-1));
66 | input.text = input.text.replace(tag, " ");
67 |
68 | // identify scope, input is #tag
69 | this.ctrl.logger.trace("Scopes defined in configuration: "+this.ctrl.config.getScopes());
70 | let scope: string | undefined = this.ctrl.config.getScopes().filter((name: string) => name === tag.trim().substring(1, tag.length)).pop();
71 |
72 |
73 | if(J.Util.isNotNullOrUndefined(scope) && scope!.length > 0) {
74 | input.scope = scope!;
75 | }
76 |
77 | this.ctrl.logger.trace("Identified scope in input: "+input.scope);
78 |
79 | });
80 |
81 |
82 | let inputForFileName: string = J.Util.normalizeFilename(input.text);
83 |
84 | Promise.all([
85 | this.ctrl.config.getNotesFilePattern(date, inputForFileName, input.scope),
86 | this.ctrl.config.getResolvedNotesPath(date, input.scope),
87 | ])
88 |
89 | .then(([fileTemplate, pathTemplate]) => {
90 | path = Path.join(pathTemplate.value!, fileTemplate.value!.trim());
91 | this.ctrl.logger.trace("Resolved path for note is", path);
92 | resolve(path);
93 | })
94 | .catch(error => {
95 | this.ctrl.logger.error(error);
96 | reject(error);
97 |
98 | });
99 |
100 | });
101 |
102 | }
103 |
104 |
105 |
106 | /**
107 | * Takes a string and separates the flag, date and text
108 | *
109 | * @param {string} inputString the value to be parsed
110 | * @returns {Promise} the resolved input object
111 | * @memberof Parser
112 | */
113 | public async parseInput(inputString: string): Promise {
114 | let inputMatcher = new J.Provider.MatchInput(this.ctrl.logger, this.ctrl.config.getLocale());
115 | return inputMatcher.parseInput(inputString);
116 |
117 | }
118 |
119 |
120 |
121 |
122 | }
123 |
124 |
--------------------------------------------------------------------------------
/src/actions/reader.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | import * as Path from 'path';
3 | import * as vscode from 'vscode';
4 | import * as J from '../';
5 | import { JournalPageType } from '../ext/conf';
6 | export interface FileEntry {
7 | path: string;
8 | name: string;
9 | scope: string;
10 | updateAt: number;
11 | createdAt: number;
12 | type: JournalPageType;
13 | }
14 | export interface BaseDirectory {
15 | path: string;
16 | scope: string;
17 | }
18 | /**
19 | * Anything which scans the files in the background goes here
20 | *
21 | */
22 | export declare class Reader {
23 | ctrl: J.Util.Ctrl;
24 | constructor(ctrl: J.Util.Ctrl);
25 | /**
26 | * Loads previous entries. This method is async and is called in combination with the sync method (which uses the threshold)
27 | *
28 | * Update: ignore threshold
29 | *
30 | * @returns {Q.Promise<[string]>}
31 | * @memberof Reader
32 | */
33 | getPreviouslyAccessedFiles(thresholdInMs: number, callback: Function, picker: any, type: JournalPageType, directories: BaseDirectory[]): Promise;
34 | getPreviouslyAccessedFilesSync(thresholdInMs: number, directories: BaseDirectory[]): Promise;
35 | /**
36 | * Tries to infer the file type from the path by matching against the configured patterns
37 | * @param entry
38 | */
39 | inferType(entry: Path.ParsedPath): JournalPageType;
40 | /**
41 | * Scans journal directory and scans for notes
42 | *
43 | * Update: Removed age threshold, take everything
44 | * Update: switched to async with readdir
45 | *
46 | * See https://medium.com/@allenhwkim/nodejs-walk-directory-f30a2d8f038f
47 | * @param dir
48 | * @param callback
49 | */
50 | private walkDir;
51 | private walkDirSync;
52 | checkDirectory(d: Date, entries: string[]): Promise;
53 | /**
54 | * Returns a list of all local files referenced in the given document.
55 | *
56 | * @param {vscode.TextDocument} doc the current journal entry
57 | * @returns {Q.Promise} an array with all references in the current journal page
58 | * @memberof Reader
59 | */
60 | getReferencedFiles(doc: vscode.TextDocument): Promise;
61 | getFilesInNotesFolderAllScopes(doc: vscode.TextDocument, date: Date): Promise;
62 | /**
63 | * Returns a list of files sitting in the notes folder for the current document (has to be a journal page)
64 | *
65 | * By making the notes folder configurable, we cannot differentiate anymore by path. We always find (and inject all notes). We therefore also check the last modification date of the file itself
66 | *
67 | * @param {vscode.TextDocument} doc the current journal entry
68 | * @returns {Q.Promise} an array with all files sitting in the directory associated with the current journal page
69 | * @memberof Reader
70 | */
71 | getFilesInNotesFolder(doc: vscode.TextDocument, date: Date, scope: string): Promise;
72 | /**
73 | * Creates or loads a note
74 | *
75 | * @param {string} path
76 | * @param {string} content
77 | * @returns {Promise}
78 | * @memberof Writer
79 | */
80 | loadNote(path: string, content: string): Promise;
81 | /**
82 | * Returns the page for a day with the given input. If the page doesn't exist yet,
83 | * it will be created (with the current date as header)
84 | *
85 | * @param {input} input with offset 0 is today, -1 is yesterday
86 | * @returns {Q.Promise} the document
87 | * @memberof Reader
88 | */
89 | loadEntryForInput(input: J.Model.Input): Promise;
90 | /**
91 | * Converts given path and filename into a full path.
92 | * @param pathname
93 | * @param filename
94 | */
95 | private resolvePath;
96 | /**
97 | * Loads the journal entry for the given date. If no entry exists, promise is rejected with the invalid path
98 | *
99 | * @param {Date} date the date for the entry
100 | * @returns {Q.Promise} the document
101 | * @throws {string} error message
102 | * @memberof Reader
103 | */
104 | loadEntryForDate(date: Date): Promise;
105 | }
106 |
--------------------------------------------------------------------------------
/src/actions/reader.ts:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2022 Patrick Maué
2 | //
3 | // This file is part of vscode-journal.
4 | //
5 | // vscode-journal is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // vscode-journal is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with vscode-journal. If not, see .
17 | //
18 |
19 | 'use strict';
20 |
21 | import * as vscode from 'vscode';
22 | import * as J from '..';
23 |
24 | export class Reader {
25 | constructor(public ctrl: J.Util.Ctrl) {
26 | }
27 |
28 |
29 | /**
30 | * Returns the page for a day with the given input. If the page doesn't exist yet,
31 | * it will be created (with the current date as header)
32 | *
33 | * @param {input} input with offset 0 is today, -1 is yesterday
34 | * @returns {Q.Promise} the document
35 | * @memberof Reader
36 | */
37 | public async loadEntryForInput(input: J.Model.Input): Promise {
38 |
39 | if (input.hasOffset()) {
40 | return this.loadEntryForDay(input.generateDate());
41 | }
42 | if (input.hasWeek()) {
43 | return this.loadEntryForWeek(input.week);
44 | }
45 | throw Error("Neither offset nor week are defined in input, we abort.");
46 |
47 | }
48 |
49 |
50 | /**
51 | * Loads the weekly page for the given week number (of the year)
52 | * @param week the week of the current year
53 | */
54 | public async loadEntryForWeek(week: Number): Promise {
55 | return new Promise((resolve, reject) => {
56 | this.ctrl.logger.trace("Entering loadEntryForWeek() in actions/reader.ts for week " + week);
57 |
58 | let path: string = "";
59 |
60 | Promise.all([
61 | this.ctrl.config.getWeekPathPattern(week),
62 | this.ctrl.config.getWeekFilePattern(week)
63 |
64 | ]).then(([pathname, filename]) => {
65 | path = J.Util.resolvePath(pathname.value!, filename.value!);
66 | return this.ctrl.ui.openDocument(path);
67 |
68 | }).catch((reason: any) => {
69 | if (reason instanceof Error) {
70 | if (!reason.message.startsWith("cannot open file:")) {
71 | this.ctrl.logger.printError(reason);
72 | reject(reason);
73 | }
74 | }
75 | return this.ctrl.writer.createWeeklyForPath(path, week);
76 |
77 | }).then((_doc: vscode.TextDocument) => {
78 | this.ctrl.logger.debug("loadEntryForWeek() - Loaded file in:", _doc.uri.toString());
79 | resolve(_doc);
80 |
81 | }).catch((error: Error) => {
82 | this.ctrl.logger.printError(error);
83 | reject("Failed to load entry for week: " + week);
84 | });
85 | });
86 | }
87 |
88 |
89 | /**
90 | * Loads the journal entry for the given date. If no entry exists, promise is rejected with the invalid path
91 | *
92 | * @param {Date} date the date for the entry
93 | * @returns {Q.Promise} the document
94 | * @throws {string} error message
95 | * @memberof Reader
96 | */
97 | public async loadEntryForDay(date: Date): Promise {
98 |
99 | return new Promise((resolve, reject) => {
100 | if (J.Util.isNullOrUndefined(date) || date!.toString().includes("Invalid")) {
101 | reject("Invalid date");
102 | return;
103 | }
104 |
105 | this.ctrl.logger.trace("Entering loadEntryforDate() in actions/reader.ts for date " + date.toISOString());
106 |
107 | let path: string = "";
108 |
109 | Promise.all([
110 | this.ctrl.config.getResolvedEntryPath(date),
111 | this.ctrl.config.getEntryFilePattern(date)
112 |
113 | ]).then(([pathname, filename]) => {
114 | path = J.Util.resolvePath(pathname.value!, filename.value!);
115 | return this.ctrl.ui.openDocument(path);
116 |
117 |
118 | }).catch((reason: any) => {
119 | if (reason instanceof Error) {
120 | if (!reason.message.startsWith("cannot open file:") && !reason.message.startsWith("cannot open vscode-remote:")) {
121 | this.ctrl.logger.printError(reason);
122 | reject(reason);
123 | }
124 | }
125 | return this.ctrl.writer.createEntryForPath(path, date);
126 |
127 | }).then((_doc: vscode.TextDocument) => {
128 | this.ctrl.logger.debug("loadEntryForDate() - Loaded file in:", _doc.uri.toString());
129 | new J.Provider.SyncNoteLinks(this.ctrl).injectAttachementLinks(_doc, date)
130 | .finally(() =>
131 | // do nothing
132 | this.ctrl.logger.trace("Scanning notes completed")
133 | );
134 | resolve(_doc);
135 |
136 | }).catch((error: Error) => {
137 | this.ctrl.logger.printError(error);
138 | reject("Failed to load entry for date: " + date.toDateString());
139 |
140 | });
141 |
142 | });
143 | }
144 |
145 | }
146 |
147 |
148 |
--------------------------------------------------------------------------------
/src/actions/writer.d.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import * as J from '../.';
3 | /**
4 | * Anything which modifies the text documents goes here.
5 | *
6 | */
7 | export declare class Writer {
8 | ctrl: J.Util.Ctrl;
9 | constructor(ctrl: J.Util.Ctrl);
10 | saveDocument(doc: vscode.TextDocument): Promise;
11 | /**
12 | * Adds the given content at the start of text document
13 | */
14 | writeHeader(doc: vscode.TextDocument, content: string): Promise;
15 | /**
16 | * Creates and saves a new file (with configured content) for a journal entry and returns the associated TextDocument
17 | *
18 | * @param {string} path
19 | * @param {Date} date
20 | * @returns {Promise}
21 | * @memberof Writer
22 | */
23 | createEntryForPath(path: string, date: Date): Promise;
24 | /**
25 | * Creates a new file, adds the given content, saves it and opens it.
26 | *
27 | * @param {string} path The path in of the new file
28 | * @param {string} content The preconfigured content of the new file
29 | * @returns {Promise} The new document associated with the file
30 | */
31 | createSaveLoadTextDocument(path: string, content: string): Promise;
32 | }
33 |
--------------------------------------------------------------------------------
/src/actions/writer.ts:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2016 Patrick Maué
2 | //
3 | // This file is part of vscode-journal.
4 | //
5 | // vscode-journal is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // vscode-journal is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with vscode-journal. If not, see .
17 | //
18 |
19 | 'use strict';
20 |
21 | import * as vscode from 'vscode';
22 | import * as J from '../.';
23 |
24 | /**
25 | * Anything which modifies the text documents goes here.
26 | *
27 | */
28 | export class Writer {
29 |
30 |
31 | constructor(public ctrl: J.Util.Ctrl) {
32 | }
33 |
34 | public async saveDocument(doc: vscode.TextDocument): Promise {
35 | return new Promise((resolve, reject) => {
36 | doc.save()
37 | .then(
38 | _success => resolve(doc),
39 | _error => reject(_error)
40 | );
41 | });
42 | }
43 |
44 |
45 | /**
46 | * Adds the given content at the start of text document
47 | */
48 | public async writeHeader(doc: vscode.TextDocument, content: string): Promise {
49 | return this.ctrl.inject.injectString(doc, content, new vscode.Position(0, 0));
50 | }
51 |
52 |
53 |
54 |
55 | /**
56 | * Creates and saves a new file (with configured content) for a journal entry and returns the associated TextDocument
57 | *
58 | * @param {string} path
59 | * @param {Date} date
60 | * @returns {Promise}
61 | * @memberof Writer
62 | */
63 | public async createEntryForPath(path: string, date: Date): Promise {
64 |
65 |
66 | return new Promise((resolve, reject) => {
67 | this.ctrl.logger.trace("Entering createEntryForPath() in ext/writer.ts for path: ", path);
68 |
69 | this.ctrl.config.getEntryTemplate(date)
70 | .then((tpl: J.Model.HeaderTemplate) => {
71 |
72 | // TODO: make this configurable (for now we keep the format hardcorded)
73 | // return J.Util.formatDate(date, tpl.template, this.ctrl.config.getLocale());
74 | return tpl.value || "";
75 | })
76 | .then((content) => {
77 | return this.ctrl.writer.createSaveLoadTextDocument(path, content);
78 | })
79 | .then((doc: vscode.TextDocument) => resolve(doc))
80 | .catch(() => reject(path));
81 | });
82 | }
83 |
84 | /**
85 | * Creates and saves a new file (with configured content) for a weekly entry and returns the associated TextDocument
86 | *
87 | * @param {string} path
88 | * @param {Number} week
89 | * @returns {Promise}
90 | * @memberof Writer
91 | */
92 | public async createWeeklyForPath(path: string, week: Number): Promise {
93 |
94 |
95 | return new Promise((resolve, reject) => {
96 | this.ctrl.logger.trace("Entering createWeeklyForPath() in ext/writer.ts for path: ", path);
97 |
98 | this.ctrl.config.getWeeklyTemplate(week)
99 | .then((tpl: J.Model.HeaderTemplate) => {
100 | return tpl.value || "";
101 | })
102 | .then((content) => {
103 | return this.ctrl.writer.createSaveLoadTextDocument(path, content);
104 | })
105 | .then((doc: vscode.TextDocument) => resolve(doc))
106 | .catch(() => reject(path));
107 | });
108 | }
109 |
110 | /**
111 | * Creates a new file, adds the given content, saves it and opens it.
112 | *
113 | * @param {string} path The path in of the new file
114 | * @param {string} content The preconfigured content of the new file
115 | * @returns {Promise} The new document associated with the file
116 | */
117 | public async createSaveLoadTextDocument(path: string, content: string): Promise {
118 |
119 | return new Promise((resolve, reject) => {
120 | this.ctrl.logger.trace("Entering createSaveLoadTextDocument() in ext/writer.ts for path: ", path);
121 | let uri: vscode.Uri = vscode.Uri.parse('untitled:' + path);
122 |
123 | this.ctrl.ui.openDocument(uri)
124 | .then((doc: vscode.TextDocument) => this.ctrl.inject.injectHeader(doc, content))
125 | .then((doc: vscode.TextDocument) => this.ctrl.ui.saveDocument(doc))
126 | .then((doc: vscode.TextDocument) => {
127 | if (doc.isUntitled) {
128 | // open it again, this time not as untitled (since it has been saved)
129 | vscode.workspace.openTextDocument(vscode.Uri.file(path))
130 | .then(doc => {
131 | this.ctrl.logger.debug("Opened new file with name: ", doc.fileName);
132 | resolve(doc);
133 | }, onRejected => reject(onRejected));
134 |
135 |
136 | } else {
137 | resolve(doc);
138 | }
139 | },
140 | failed=> {
141 | this.ctrl.logger.error("Failed to create file: ", uri.toString(), " with reason: ", failed);
142 | reject(failed);
143 | }
144 | )
145 | .catch(onRejected => {
146 | reject(onRejected);
147 | });
148 | });
149 |
150 |
151 |
152 |
153 | }
154 |
155 | }
--------------------------------------------------------------------------------
/src/ext/commands.d.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import * as J from '../.';
3 | export interface Commands {
4 | processInput(): Promise;
5 | showNote(): Promise;
6 | showEntry(offset: number): Promise;
7 | loadJournalWorkspace(): Promise;
8 | printSum(): Promise;
9 | printDuration(): Promise;
10 | printTime(): Promise;
11 | runTestFeature(): Promise;
12 | }
13 | export declare class JournalCommands implements Commands {
14 | ctrl: J.Util.Ctrl;
15 | /**
16 | *
17 | */
18 | constructor(ctrl: J.Util.Ctrl);
19 | /**
20 | * Opens the editor for a specific day. Supported values are explicit dates (in ISO format),
21 | * offsets (+ or - as prefix and 0) and weekdays (next wednesday)
22 | *
23 | * Update: supports much more now
24 | */
25 | processInput(): Promise;
26 | /**
27 | * Called by command 'Journal:open'. Opens a new windows with the Journal base directory as root.
28 | *
29 | * @returns {Q.Promise}
30 | * @memberof JournalCommands
31 | */
32 | loadJournalWorkspace(): Promise;
33 | /**
34 | * Prints the sum of the selected numbers in the current editor at the selection location
35 | */
36 | printSum(): Promise;
37 | /**
38 | * Prints the current time at the cursor postion
39 | *
40 | * @returns {Q.Promise}
41 | * @memberof JournalCommands
42 | */
43 | printTime(): Promise;
44 | /**
45 | * Called by command 'Journal:printDuration'. Requires three selections (three active cursors)
46 | * in current document. It identifies which of the selections are times (in the format hh:mm
47 | * or glued like "1223") and where to print the duration (in decimal form).
48 | * For now the duration is always printing hours.
49 | *
50 | * @returns {Q.Promise}
51 | * @memberof JournalCommands
52 | */
53 | printDuration(): Promise;
54 | /**
55 | * Implements commands "yesterday", "today", "yesterday", where the input is predefined (no input box appears)
56 | * @param offset
57 | */
58 | showEntry(offset: number): Promise;
59 | /**
60 | * Creates a new file in a subdirectory with the current day of the month as name.
61 | * Shows the file to let the user start adding notes right away.
62 | *
63 | * @returns {Q.Promise}
64 | * @memberof JournalCommands
65 | */
66 | showNote(): Promise;
67 | runTestFeature(): Promise;
68 | showError(error: string | Promise | Error): void;
69 | private showErrorInternal;
70 | /**
71 | * Expects any user input from the magic input and either opens the file or creates it.
72 | * @param input
73 | */
74 | private loadPageForInput;
75 | }
76 |
--------------------------------------------------------------------------------
/src/ext/index.d.ts:
--------------------------------------------------------------------------------
1 | export { VSCode } from './vscode';
2 | export { JournalCodeLensProvider } from './vscode-codelens';
3 | export { Commands, JournalCommands } from './commands';
4 | export { Startup } from './startup';
5 | export { Configuration, InlineTemplate, ScopedTemplate, HeaderTemplate, SCOPE_DEFAULT } from './conf';
6 |
--------------------------------------------------------------------------------
/src/ext/index.ts:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2017 Patrick Maué
2 | //
3 | // This file is part of vscode-journal.
4 | //
5 | // vscode-journal is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // vscode-journal is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with vscode-journal. If not, see .
17 | //
18 |
19 | // export { JournalCompletionProvider, JournalActionsProvider } from './provider';
20 |
21 | export {
22 | getInputDetailsStringForEntry,
23 | getInputDetailsStringForMemo,
24 | getInputDetailsStringForTask,
25 | getInputDetailsStringForTaskInWeek,
26 | getInputDetailsStringForWeekly,
27 | getInputDetailsTranslation,
28 | getInputLabelTranslation,
29 | getPickDetailsTranslation
30 |
31 | } from './translations';
32 | export { Dialogues } from './dialogues';
33 | export { JournalCodeLensProvider } from './vscode-codelens';
34 | export { Startup } from './startup';
35 | export {
36 | Configuration,
37 | SCOPE_DEFAULT,
38 | } from './conf';
39 |
--------------------------------------------------------------------------------
/src/ext/startup.d.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import * as J from '..';
3 | export declare class Startup {
4 | context: vscode.ExtensionContext;
5 | config: vscode.WorkspaceConfiguration;
6 | /**
7 | *
8 | */
9 | constructor(context: vscode.ExtensionContext, config: vscode.WorkspaceConfiguration);
10 | initialize(): Promise;
11 | registerLoggingChannel(ctrl: J.Util.Ctrl, context: vscode.ExtensionContext): Promise;
12 | registerCodeLens(ctrl: J.Util.Ctrl, context: vscode.ExtensionContext): Promise;
13 | registerCommands(ctrl: J.Util.Ctrl, context: vscode.ExtensionContext): Promise;
14 | /**
15 | * Sets default syntax highlighting settings on startup, we try to differentiate between dark and light themes
16 | *
17 | * @param {J.Util.Ctrl} ctrl
18 | * @param {vscode.ExtensionContext} context
19 | * @returns {Q.Promise}
20 | * @memberof Startup
21 | */
22 | registerSyntaxHighlighting(ctrl: J.Util.Ctrl): Promise;
23 | }
24 |
--------------------------------------------------------------------------------
/src/ext/translations.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import * as J from '..';
3 |
4 | import messages from './messages.json';
5 |
6 | type Messages = {
7 | [locale: string]: {
8 | [category: string]: {
9 | [code: string]: string;
10 | };
11 | };
12 | };
13 |
14 |
15 |
16 | /**
17 | * Fetches a translation for the given category and code.
18 | * Falls back to English if the translation does not exist in the user's locale.
19 | *
20 | * @param category - The translation category (e.g., "descriptions", "labels", "picks", "details").
21 | * @param code - The code that identifies the specific translation string.
22 | * @returns The translated string, or the English fallback if not found.
23 | */
24 | function getTranslation(category: string, code: string): string {
25 | const translations: Messages = messages;
26 | const locale = vscode.env.language.substring(0, 2); // Get the first two letters of the locale (e.g., "en", "de")
27 |
28 | // Attempt to retrieve the translation from the user's locale
29 | const translationCategory = translations[locale]?.[category] || translations['en']?.[category]; // Default to English if locale not found
30 |
31 | // Return the specific translation code from the user's locale or fallback to the English version
32 | return translationCategory[code] || translations['en'][category][code];
33 | }
34 |
35 | /**
36 | * Returns the description based on the code provided.
37 | * Always returns a fallback in English if no translation is found for the user's locale.
38 | *
39 | * @param code - The code of the description string.
40 | * @returns The description string.
41 | */
42 | export function getInputDetailsTranslation(code: number): string {
43 | return getTranslation('descriptions', code.toString());
44 | }
45 |
46 | /**
47 | * Returns the label based on the code provided.
48 | * Always returns a fallback in English if no translation is found for the user's locale.
49 | *
50 | * @param code - The code of the label string.
51 | * @returns The label string.
52 | */
53 | export function getInputLabelTranslation(code: number): string {
54 | return getTranslation('labels', code.toString());
55 | }
56 |
57 | /**
58 | * Returns the pick details based on the code provided.
59 | * Always returns a fallback in English if no translation is found for the user's locale.
60 | *
61 | * @param code - The code of the pick details string.
62 | * @returns The pick details string.
63 | */
64 | export function getPickDetailsTranslation(code: number): string {
65 | return getTranslation('picks', code.toString());
66 | }
67 |
68 | /**
69 | * Returns the task details string for a specific day.
70 | * Always returns a fallback in English if no translation is found for the user's locale.
71 | *
72 | * @param dayAsString - The day string (e.g., "Monday", "Tuesday").
73 | * @returns The task details string.
74 | */
75 | export function getInputDetailsStringForTask(dayAsString: string): string {
76 | const translation = getTranslation('details', 'task');
77 | return translation.replace("{day}", dayAsString);
78 | }
79 |
80 | /**
81 | * Returns the task details string for a specific week.
82 | * Always returns a fallback in English if no translation is found for the user's locale.
83 | *
84 | * @param weekAsNumber - The week number (e.g., "32").
85 | * @returns The task details string for the specified week.
86 | */
87 | export function getInputDetailsStringForTaskInWeek(weekAsNumber: number): string {
88 | const translation = getTranslation('details', 'taskInWeek');
89 | return translation.replace("{week}", weekAsNumber.toString());
90 | }
91 |
92 | /**
93 | * Returns the weekly details string for a specific week.
94 | * Always returns a fallback in English if no translation is found for the user's locale.
95 | *
96 | * @param week - The week number.
97 | * @returns The weekly details string.
98 | */
99 | export function getInputDetailsStringForWeekly(week: number): string {
100 | const translation = getTranslation('details', 'weekly');
101 | return translation.replace("{week}", week.toString());
102 | }
103 |
104 | /**
105 | * Returns the entry details string for a specific day.
106 | * Always returns a fallback in English if no translation is found for the user's locale.
107 | *
108 | * @param dayAsString - The day string (e.g., "Monday", "Tuesday").
109 | * @returns The entry details string.
110 | */
111 | export function getInputDetailsStringForEntry(dayAsString: string): string {
112 | const translation = getTranslation('details', 'entry');
113 | return translation.replace("{day}", dayAsString);
114 | }
115 |
116 | /**
117 | * Returns the memo details string for a specific day.
118 | * Always returns a fallback in English if no translation is found for the user's locale.
119 | *
120 | * @param dayAsString - The day string (e.g., "Monday", "Tuesday").
121 | * @returns The memo details string.
122 | */
123 | export function getInputDetailsStringForMemo(dayAsString: string): string {
124 | const translation = getTranslation('details', 'memo');
125 | return translation.replace("{day}", dayAsString);
126 | }
127 |
--------------------------------------------------------------------------------
/src/ext/vscode-codelens.ts:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2021 Patrick Maué
2 | //
3 | // This file is part of vscode-journal.
4 | //
5 | // vscode-journal is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // vscode-journal is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with vscode-journal. If not, see .
17 | //
18 | 'use strict';
19 |
20 | import * as vscode from 'vscode';
21 | import * as J from '../.';
22 |
23 | export class JournalCodeLensProvider implements vscode.CodeLensProvider {
24 | private codeLenses: vscode.CodeLens[] = [];
25 | private ctrl: J.Util.Ctrl;
26 |
27 | private _onDidChangeCodeLenses: vscode.EventEmitter = new vscode.EventEmitter();
28 |
29 |
30 |
31 | constructor(ctrl: J.Util.Ctrl) {
32 | this.ctrl = ctrl;
33 |
34 | vscode.workspace.onDidChangeConfiguration((_) => {
35 | this._onDidChangeCodeLenses.fire();
36 | });
37 | }
38 |
39 | async getRegex() : Promise {
40 | let template = await this.ctrl.config.getTaskInlineTemplate();
41 | return new RegExp(template.after);
42 | }
43 |
44 | public async provideCodeLenses(document: vscode.TextDocument, token: vscode.CancellationToken): Promise {
45 | this.codeLenses = [];
46 | const regex = await this.getRegex();
47 | const text = document.getText();
48 | const matches = regex.exec(text);
49 |
50 | if(matches !== null) {
51 | const line = document.lineAt(document.positionAt(matches.index).line);
52 | const indexOf = line.text.indexOf(matches[0]);
53 | const position = new vscode.Position(line.lineNumber, indexOf);
54 | const range = document.getWordRangeAtPosition(position, regex);
55 | if (range) {
56 | this.codeLenses.push(new vscode.CodeLens(range));
57 | }
58 | }
59 |
60 | return this.codeLenses;
61 | }
62 |
63 | public resolveCodeLens?(codeLens: vscode.CodeLens, token: vscode.CancellationToken):
64 | vscode.CodeLens | Thenable {
65 |
66 |
67 | codeLens.command = {
68 | title: "Collect all tasks",
69 | tooltip: "Collect and modify tasks from this and previous journal entries",
70 | command: "codelens-sample.codelensAction",
71 | arguments: ["Argument 1", false]
72 | };
73 | return codeLens;
74 | }
75 | }
--------------------------------------------------------------------------------
/src/ext/vscode.d.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import * as J from './..';
3 | import { JournalPageType } from './conf';
4 | import { FileEntry } from '../actions/reader';
5 | interface DecoratedQuickPickItem extends vscode.QuickPickItem {
6 | parsedInput?: J.Model.Input;
7 | replace?: boolean;
8 | path: string;
9 | pickItem?: JournalPageType;
10 | fileEntry?: FileEntry;
11 | }
12 | /**
13 | * Anything which extends Visual Studio Code goes here
14 | *
15 | */
16 | export declare class VSCode {
17 | ctrl: J.Util.Ctrl;
18 | constructor(ctrl: J.Util.Ctrl);
19 | /**
20 | *
21 | */
22 | getUserInputWithValidation(): Promise;
23 | private generateDescription;
24 | private generateDetail;
25 | /**
26 | * Callback function for filewalker to add an item to our quickpick list
27 | *
28 | * @param fe
29 | */
30 | addItem(fe: FileEntry, input: vscode.QuickPick, type: JournalPageType): void;
31 | /**
32 | *
33 | * @param type
34 | */
35 | pickItem(type: JournalPageType): Promise;
36 | /**
37 | * Simple method to have Q Promise for vscode API call to get user input
38 | */
39 | getUserInput(tip: string): Promise;
40 | saveDocument(textDocument: vscode.TextDocument): Promise;
41 | openDocument(path: string | vscode.Uri): Promise;
42 | /**
43 | * Shows the given document in Visual Studio Code
44 | *
45 | * @param {vscode.TextDocument} textDocument the document to show
46 | * @returns {vscode.TextEditor} the associated text editor
47 | * @memberOf VsCode
48 | */
49 | showDocument(textDocument: vscode.TextDocument): Promise;
50 | }
51 | export {};
52 |
--------------------------------------------------------------------------------
/src/extension.d.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import * as J from './';
3 | export declare var journalStartup: J.Extension.Startup;
4 | export declare var journalConfiguration: J.Extension.Configuration;
5 | export declare function activate(context: vscode.ExtensionContext): {
6 | getJournalConfiguration(): J.Extension.Configuration;
7 | };
8 | export declare function deactivate(): void;
9 |
--------------------------------------------------------------------------------
/src/extension.ts:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2018 Patrick Maué
2 | //
3 | // This file is part of vscode-journal.
4 | //
5 | // vscode-journal is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // vscode-journal is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with vscode-journal. If not, see .
17 | //
18 |
19 | 'use strict';
20 |
21 |
22 | import * as vscode from 'vscode';
23 | import * as J from './';
24 |
25 | export var journalStartup: J.Extension.Startup;
26 | export var journalConfiguration: J.Extension.Configuration;
27 |
28 | export function activate(context: vscode.ExtensionContext) {
29 |
30 | try {
31 | console.time("startup");
32 |
33 | let config: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("journal");
34 | journalStartup = new J.Extension.Startup(config);
35 | journalStartup.run(context);
36 |
37 | // return public API of this extension
38 | return {
39 | getJournalConfiguration() {
40 | return journalStartup.getJournalController().config;
41 | }
42 | };
43 | } catch (error) {
44 | console.error("Failed to start journal extension with reason: ", error);
45 | throw error;
46 | }
47 |
48 | }
49 |
50 |
51 | // this method is called when your extension is deactivated
52 | export function deactivate() {
53 | }
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/src/index.d.ts:
--------------------------------------------------------------------------------
1 | import * as Extension from './ext';
2 | import * as Model from './model';
3 | import * as Actions from './actions';
4 | import * as Util from './util';
5 | import * as Features from './features';
6 | export { Model, Extension, Actions, Util, Features };
7 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2018 Patrick Maué
2 | //
3 | // This file is part of vscode-journal.
4 | //
5 | // vscode-journal is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // vscode-journal is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with vscode-journal. If not, see .
17 | //
18 |
19 |
20 | import * as Extension from './ext';
21 | import * as Model from './model';
22 | import * as Actions from './actions';
23 | import * as Util from './util';
24 | import * as Provider from './provider';
25 |
26 | // export { Commons, Extension, Model, Actions, Journal, JournalMain };
27 | export {Model, Extension, Actions, Util, Provider};
28 |
--------------------------------------------------------------------------------
/src/model/config.ts:
--------------------------------------------------------------------------------
1 | export enum JournalPageType {
2 | note,
3 | entry,
4 | attachement
5 | }
6 |
7 | export interface ScopedTemplate {
8 | name?: string;
9 | scope?: string;
10 | template: string;
11 | value?: string;
12 | }
13 |
14 |
15 |
16 | export interface FilePattern extends ScopedTemplate {
17 | type: JournalPageType;
18 | }
19 |
20 | export interface PathTemplate extends ScopedTemplate {
21 | type: JournalPageType;
22 | }
23 |
24 | export interface HeaderTemplate extends ScopedTemplate {
25 | }
26 |
27 | export interface InlineTemplate extends ScopedTemplate {
28 | after: string;
29 | }
--------------------------------------------------------------------------------
/src/model/files.ts:
--------------------------------------------------------------------------------
1 |
2 | import * as J from './..';
3 |
4 | export interface FileEntry {
5 | path: string;
6 | name: string;
7 | scope?: string;
8 | updateAt: number;
9 | createdAt: number;
10 | accessedAt: number;
11 | type?: J.Model.JournalPageType;
12 | }
--------------------------------------------------------------------------------
/src/model/index.ts:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2018 Patrick Maué
2 | //
3 | // This file is part of vscode-journal.
4 | //
5 | // vscode-journal is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // vscode-journal is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with vscode-journal. If not, see .
17 | //
18 |
19 |
20 | export { HeaderTemplate, InlineTemplate, JournalPageType, ScopedTemplate } from './config';
21 | export { InlineString } from './inline';
22 | export { Input, SelectedInput, NoteInput } from './input';
23 | export { TemplateInfo, ScopeDirectory } from './templates';
24 | export { FileEntry } from "./files";
25 | export { DecoratedQuickPickItem, TimedQuickPick } from "./vscode";
26 |
27 |
--------------------------------------------------------------------------------
/src/model/inline.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 |
3 | export interface InlineString {
4 | position: vscode.Position;
5 | value: string;
6 | document: vscode.TextDocument;
7 |
8 | }
--------------------------------------------------------------------------------
/src/model/input.d.ts:
--------------------------------------------------------------------------------
1 | export declare class Input {
2 | private _offset;
3 | private _flags;
4 | private _text;
5 | private _scope;
6 | private _tags;
7 | constructor(offset?: number);
8 | /**
9 | * Getter offset
10 | * @return {number }
11 | */
12 | get offset(): number;
13 | get tags(): string[];
14 | /**
15 | * Getter flags
16 | * @return {string }
17 | */
18 | get flags(): string;
19 | /**
20 | * Getter text
21 | * @return {string }
22 | */
23 | get text(): string;
24 | /**
25 | * Getter scope
26 | * @return {string }
27 | */
28 | get scope(): string;
29 | /**
30 | * Setter offset
31 | * @param {number } value
32 | */
33 | set offset(value: number);
34 | /**
35 | * Setter flags
36 | * @param {string } value
37 | */
38 | set flags(value: string);
39 | /**
40 | * Setter text
41 | * @param {string } value
42 | */
43 | set text(value: string);
44 | set tags(values: string[]);
45 | /**
46 | * Setter scope
47 | * @param {string } value
48 | */
49 | set scope(value: string);
50 | hasMemo(): boolean;
51 | hasFlags(): boolean;
52 | hasOffset(): boolean;
53 | hasTask(): boolean;
54 | generateDate(): Date;
55 | }
56 | export declare class NoteInput extends Input {
57 | private _path;
58 | constructor();
59 | get path(): string;
60 | set path(path: string);
61 | }
62 | export declare class SelectedInput extends Input {
63 | private _selected;
64 | private _path;
65 | get selected(): boolean;
66 | get path(): string;
67 | constructor(path: string);
68 | }
69 |
--------------------------------------------------------------------------------
/src/model/input.ts:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2018 Patrick Maué
2 | //
3 | // This file is part of vscode-journal.
4 | //
5 | // vscode-journal is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // vscode-journal is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with vscode-journal. If not, see .
17 | //
18 |
19 |
20 | 'use strict';
21 |
22 | import { isNullOrUndefined } from "../util/util";
23 |
24 | export class Input {
25 |
26 |
27 |
28 | private _offset: number;
29 | private _flags: string = "";
30 | private _text: string = "";
31 | private _scope: string = "";
32 | private _week: number;
33 |
34 | private _tags: string[] = [];
35 |
36 |
37 |
38 | constructor(offset?: number) {
39 | this._offset = (isNullOrUndefined(offset)) ? 0 : offset!;
40 | this._week = -1;
41 | }
42 |
43 |
44 | /**
45 | * Getter offset
46 | * @return {number }
47 | */
48 | public get offset(): number {
49 | return this._offset;
50 | }
51 |
52 | public get tags(): string[] {
53 | return this._tags;
54 | }
55 |
56 | /**
57 | * Getter flags
58 | * @return {string }
59 | */
60 | public get flags(): string {
61 | return this._flags;
62 | }
63 |
64 | /**
65 | * Getter text
66 | * @return {string }
67 | */
68 | public get text(): string {
69 | return this._text;
70 | }
71 |
72 | /**
73 | * Getter scope
74 | * @return {string }
75 | */
76 | public get scope(): string {
77 | return this._scope;
78 | }
79 |
80 | /**
81 | * Setter offset
82 | * @param {number } value
83 | */
84 | public set offset(value: number ) {
85 | this._offset = value;
86 | }
87 |
88 | /**
89 | * Setter flags
90 | * @param {string } value
91 | */
92 | public set flags(value: string ) {
93 | this._flags = value;
94 | }
95 |
96 | /**
97 | * Setter text
98 | * @param {string } value
99 | */
100 | public set text(value: string ) {
101 | this._text = value;
102 | }
103 |
104 | public set tags(values: string[]) {
105 | this._tags = values;
106 | }
107 |
108 | /**
109 | * Setter scope
110 | * @param {string } value
111 | */
112 | public set scope(value: string ) {
113 | this._scope = value;
114 | }
115 |
116 | /**
117 | * Return the week of year
118 | */
119 | public get week(): number {
120 | return this._week;
121 | }
122 | public set week(value: number) {
123 | this._week = value;
124 | }
125 |
126 |
127 | public hasMemo(): boolean {
128 | return (this._text !== undefined) && this._text.length > 0;
129 | }
130 |
131 | public hasWeek() : boolean {
132 | return (this._week >= 0);
133 | }
134 |
135 | public hasFlags(): boolean {
136 | let res = (this._flags !== undefined) && (this._flags.length > 0);
137 | return res;
138 | }
139 |
140 | public hasOffset(): boolean {
141 | return !isNaN(this.offset) && this._week === -1;
142 | }
143 |
144 | public hasTask(): boolean {
145 | let matches: RegExpMatchArray | null = this.flags.match("task|todo");
146 | return (matches !== null && matches.length > 0);
147 | }
148 |
149 | public hasText() {
150 | return this._text.length > 0;
151 | }
152 |
153 | public generateDate(): Date {
154 | let date = new Date();
155 | date.setDate(date.getDate() + this.offset);
156 | return date;
157 |
158 | }
159 |
160 |
161 |
162 | }
163 |
164 | export class NoteInput extends Input {
165 |
166 | private _path: string = "";
167 |
168 | constructor() {
169 | super(0);
170 | }
171 |
172 | public get path() {return this._path;}
173 | public set path( path: string ) {this._path = path;}
174 |
175 | }
176 |
177 | export class SelectedInput extends Input {
178 |
179 | private _selected: boolean = false; // if selected from quickpick
180 | private _path: string = "";
181 |
182 |
183 | public get selected() {return this._selected;}
184 | public get path() {return this._path;}
185 |
186 | constructor(path: string) {
187 | super(0);
188 | this._selected = true;
189 | this._path = path;
190 | }
191 |
192 |
193 |
194 |
195 | }
196 |
--------------------------------------------------------------------------------
/src/model/templates.ts:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2018 Patrick Maué
2 | //
3 | // This file is part of vscode-journal.
4 | //
5 | // vscode-journal is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // vscode-journal is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with vscode-journal. If not, see .
17 | //
18 |
19 |
20 | export interface TemplateInfo {
21 | template: string;
22 | after: string;
23 | }
24 |
25 |
26 |
27 | export interface ScopeDirectory {
28 | path: string;
29 | scope: string;
30 |
31 |
32 | }
--------------------------------------------------------------------------------
/src/model/vscode.ts:
--------------------------------------------------------------------------------
1 | import { AnyARecord } from 'dns';
2 | import * as vscode from 'vscode';
3 | import * as J from '..';
4 |
5 | export interface TimedQuickPick extends vscode.QuickPick {
6 | start?: number;
7 | }
8 |
9 |
10 | export interface DecoratedQuickPickItem extends vscode.QuickPickItem {
11 | parsedInput?: J.Model.Input;
12 | replace?: boolean;
13 | path: string;
14 | pickItem?: J.Model.JournalPageType;
15 | fileEntry?: J.Model.FileEntry;
16 | }
17 |
18 | export interface TextMateRule {
19 | scope: string;
20 | settings: any;
21 | }
--------------------------------------------------------------------------------
/src/provider/InputMatcher.d.ts:
--------------------------------------------------------------------------------
1 | import { Logger } from "../util/logger";
2 | import { Input } from "../model/input";
3 | export declare class InputMatcher {
4 | logger: Logger;
5 | today: Date;
6 | private scopeExpression;
7 | private expr;
8 | constructor(logger: Logger);
9 | /**
10 | * Takes a string and separates the flag, date and text
11 | *
12 | * @param {string} inputString the value to be parsed
13 | * @param {boolean} replaceSpecialCharacters if special characters like the # have to be normalized (e.g. for file names)
14 | * @returns {Q.Promise} the resolved input object
15 | * @memberof Parser
16 | */
17 | parseInput(inputString: string): Promise;
18 | /**
19 | * If tags are present in the input string, extract them if these are configured scopes
20 | *
21 | * @private
22 | * @param {string[]} values
23 | * @returns {string}
24 | * @memberof Parser
25 | */
26 | private extractTags;
27 | private extractText;
28 | private extractFlags;
29 | private extractOffset;
30 | private resolveOffsetString;
31 | private resolveShortcutString;
32 | /**
33 | * Resolves an ISO String and returns the offset to the current day
34 | *
35 | * @param inputString a date formatted as iso string, e.g. 06-22
36 | * @returns the offset to the current day
37 | */
38 | private resolveISOString;
39 | /**
40 | * Resolves the weekday for a given string. Allowed strings are monday to friday. If a modifier is present
41 | * ("next" or "last"), it will return the according weekdey of last or next week.
42 | *
43 | * @param weekday the weekday as a string
44 | * @param mod next or last
45 | * @returns the offset to the current day as number
46 | */
47 | private resolveWeekday;
48 | /**
49 | * Takes any given string as input and tries to compute the offset from today's date.
50 | * It translates something like "next wednesday" into "4" (if next wednesday is in four days).
51 | *
52 | * @param {string} value the string to be processed
53 | * @returns {Q.Promise} the resolved offeset
54 | * @memberof Parser
55 | */
56 | private getExpression;
57 | }
58 |
--------------------------------------------------------------------------------
/src/provider/codeactions/for-completed-tasks.ts:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2021 Patrick Maué
2 | //
3 | // This file is part of vscode-journal.
4 | //
5 | // vscode-journal is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // vscode-journal is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with vscode-journal. If not, see .
17 | //
18 | 'use strict';
19 |
20 | import * as vscode from 'vscode';
21 | import * as J from '../..';
22 |
23 |
24 | /**
25 | * The complete task codelens is active for open tasks, e.g. '-[ ] some text'
26 | *
27 | * Once activated, it will
28 | * - close the task: '-[ ] some text' -> '-[x] some text'
29 | * - annotate the task with completion date: '-[x] some text (completed on 2021-05-12 at 12:12)'
30 | */
31 | export class CompletedTaskActions implements vscode.CodeActionProvider {
32 | private ctrl: J.Util.Ctrl;
33 | private regex = new RegExp(/-\s{0,1}\[\s{0,2}x|X\s{0,2}\].*/g);
34 |
35 |
36 | public static readonly providedCodeActionKinds = [
37 | vscode.CodeActionKind.QuickFix
38 | ];
39 |
40 |
41 | constructor(ctrl: J.Util.Ctrl) {
42 | this.ctrl = ctrl;
43 | }
44 |
45 | public provideCodeActions(document: vscode.TextDocument, range: vscode.Range | vscode.Selection, context: vscode.CodeActionContext, token: vscode.CancellationToken): vscode.ProviderResult<(vscode.CodeAction | vscode.Command)[]> {
46 | try {
47 | if(! this.matchesExpression(document, range)) {
48 | return;
49 | }
50 | return Promise.all([
51 | this.createReinstateTask(document, range)
52 | ]
53 | );
54 | } catch (error: any) {
55 | throw new Error(error);
56 | }
57 | }
58 |
59 |
60 | private createReinstateTask(document: vscode.TextDocument, range: vscode.Range | vscode.Selection): vscode.CodeAction {
61 | try {
62 | const fix = new vscode.CodeAction(`Open this task again`, vscode.CodeActionKind.QuickFix);
63 |
64 | fix.edit = new vscode.WorkspaceEdit();
65 | fix.edit.replace(document.uri, this.getTaskBoxRange(document, range) , "[ ]");
66 | fix.edit.delete(document.uri, this.getAnnotationRange(document, range));
67 | return fix;
68 |
69 | } catch (error) {
70 | throw error;
71 | }
72 | }
73 |
74 | private getAnnotationRange(document: vscode.TextDocument, range: vscode.Range | vscode.Selection): vscode.Range {
75 | const line: vscode.TextLine = document.lineAt(range.start.line);
76 | const start: number = line.text.indexOf(" (done: ");
77 | const end: number = line.text.substr(start).indexOf(")")+start+1;
78 | return new vscode.Range(range.start.line, start, range.end.line, end);
79 |
80 | }
81 | private getTaskBoxRange(document: vscode.TextDocument, range: vscode.Range | vscode.Selection ): vscode.Range {
82 | const line: vscode.TextLine = document.lineAt(range.start.line);
83 | return new vscode.Range(range.start.line, line.text.indexOf("["), range.end.line,line.text.indexOf("]")+1);
84 | }
85 |
86 |
87 |
88 | private matchesExpression(document: vscode.TextDocument, range: vscode.Range): boolean {
89 | return document.lineAt(range.start.line).text.match(this.regex) !== null;
90 | }
91 |
92 |
93 |
94 | }
--------------------------------------------------------------------------------
/src/provider/codeactions/for-open-tasks.ts:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2021 Patrick Maué
2 | //
3 | // This file is part of vscode-journal.
4 | //
5 | // vscode-journal is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // vscode-journal is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with vscode-journal. If not, see .
17 | //
18 | 'use strict';
19 |
20 | import moment = require('moment');
21 | import * as vscode from 'vscode';
22 | import * as J from '../..';
23 | import { ShiftTarget } from '../commands/copy-task';
24 |
25 |
26 | /**
27 | * The complete task codelens is active for open tasks, e.g. '-[ ] some text'
28 | *
29 | * Once activated, it will
30 | * - close the task: '-[ ] some text' -> '-[x] some text'
31 | * - annotate the task with completion date: '-[x] some text (completed on 2021-05-12 at 12:12)'
32 | */
33 | export class OpenTaskActions implements vscode.CodeActionProvider {
34 | private ctrl: J.Util.Ctrl;
35 | private regex = new RegExp(/-\s{0,1}\[\s{0,2}\].*/g);
36 |
37 |
38 | public static readonly providedCodeActionKinds = [
39 | vscode.CodeActionKind.QuickFix
40 | ];
41 |
42 |
43 | constructor(ctrl: J.Util.Ctrl) {
44 | this.ctrl = ctrl;
45 | }
46 |
47 |
48 | provideCodeActions(document: vscode.TextDocument, range: vscode.Range | vscode.Selection, context: vscode.CodeActionContext, token: vscode.CancellationToken): vscode.ProviderResult<(vscode.CodeAction)[]> {
49 |
50 | try {
51 | if (!this.isOpenTask(document, range)) { return; }
52 | return Promise.all([
53 | this.createCompleteTaskAction(`Complete this task`, document, range),
54 | this.createShiftTaskAction(`Plan for the next working day`, document, range, ShiftTarget.nextWorkingDay),
55 | this.createShiftTaskAction(`Plan for tomorrow`, document, range, ShiftTarget.tomorrow),
56 | this.createShiftTaskAction(`Plan for today`, document, range, ShiftTarget.today)
57 | ]
58 | );
59 | } catch (error: any) {
60 | throw new Error(error);
61 | }
62 | }
63 |
64 | private async createCompleteTaskAction(description: string, document: vscode.TextDocument, range: vscode.Range | vscode.Selection): Promise {
65 | try {
66 | const fix = new vscode.CodeAction(description, vscode.CodeActionKind.QuickFix);
67 |
68 | fix.edit = new vscode.WorkspaceEdit();
69 | fix.edit.replace(document.uri, this.getTaskBoxRange(document, range), "[x]");
70 |
71 | const time = moment().format("YYYY-MM-DD HH:mm");
72 |
73 | // FIXME: if current document is not current day, we need to insert also the current date (not only time)
74 |
75 | fix.edit.insert(document.uri, document.lineAt(range.start.line).range.end, " (done: " + time + ")");
76 |
77 | return fix;
78 |
79 | } catch (error) {
80 | throw error;
81 | }
82 | }
83 |
84 | private async createShiftTaskAction(description: string, document: vscode.TextDocument, range: vscode.Range | vscode.Selection, target: ShiftTarget): Promise {
85 | try {
86 | const fix = new vscode.CodeAction(description, vscode.CodeActionKind.QuickFix);
87 |
88 | fix.edit = new vscode.WorkspaceEdit();
89 | fix.edit.replace(document.uri, this.getTaskBoxRange(document, range), "[>]");
90 | fix.edit.insert(document.uri, document.lineAt(range.end).range.end, this.getCopyText(target));
91 | fix.command = { command: "journal.commands.copy-task", title: 'Copy a task', tooltip: 'Copy a task to another entry.', arguments: [document, await this.getTaskText(document, range), target] };
92 | return fix;
93 |
94 | } catch (error) {
95 | throw error;
96 | }
97 | }
98 |
99 |
100 | private async getTaskText(document: vscode.TextDocument, range: vscode.Range | vscode.Selection): Promise {
101 | const line: vscode.TextLine = document.lineAt(range.start.line);
102 | let text = line.text.trim();
103 | const tpl: J.Model.InlineTemplate = await this.ctrl.config.getTaskInlineTemplate();
104 |
105 | // line: - [ ] Task: this is some text blabla
106 | // template: - [ ] Task: {$input} blabla
107 |
108 | const start = tpl.template.indexOf("${input}");
109 | const end = tpl.template.indexOf("${input}")+8;
110 |
111 | const prefix = tpl.template.substring(0, start);
112 | const postfix = tpl.template.substring(end, tpl.template.length);
113 |
114 | text = text.replace(prefix, "");
115 | text = text.replace(postfix, "");
116 |
117 | // a task might have been created manually (it doesn't match the template). In this case, we still need to remove the any variation of "- [ ]"
118 | text = text.replace(/-\s?\[\s?\]/, "");
119 | text = text.trim();
120 |
121 | return text;
122 | }
123 |
124 | private getTaskBoxRange(document: vscode.TextDocument, range: vscode.Range | vscode.Selection): vscode.Range {
125 | const line: vscode.TextLine = document.lineAt(range.start.line);
126 | return new vscode.Range(range.start.line, line.text.indexOf("["), range.end.line, line.text.indexOf("]") + 1);
127 | }
128 |
129 |
130 |
131 |
132 | private isOpenTask(document: vscode.TextDocument, range: vscode.Range): boolean {
133 | return document.lineAt(range.start.line).text.match(this.regex) !== null;
134 | }
135 |
136 | private getCopyText(target: ShiftTarget): string {
137 |
138 | switch (target) {
139 | case ShiftTarget.nextWorkingDay: return " (moved: next work day)";
140 | case ShiftTarget.today: return (" (moved: "+moment().format("YYYY-MM-DD")+")");
141 | case ShiftTarget.tomorrow: return (" (moved: "+moment().add(1, "d").format("YYYY-MM-DD")+")");
142 | case ShiftTarget.successorDay: return (" (moved: somewhere else");
143 | }
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/src/provider/codelens/migrate-tasks.ts:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2021 Patrick Maué
2 | //
3 | // This file is part of vscode-journal.
4 | //
5 | // vscode-journal is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // vscode-journal is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with vscode-journal. If not, see .
17 | //
18 | 'use strict';
19 |
20 | import * as vscode from 'vscode';
21 | import * as J from '../..';
22 |
23 |
24 | /**
25 | * The migrate task codelens is only active for the tasks header (as configured in settings, default is '## Tasks') for today's journal entry.
26 | *
27 | * Once activated, it scans the previous entries (last 20 entries) and copies any open tasks to today's entry.
28 | * For each identified open task, it will trigger the according shift action for the given range.
29 | *
30 | *
31 | */
32 | export class MigrateTasksCodeLens implements vscode.CodeLensProvider {
33 | private codeLenses: vscode.CodeLens[] = [];
34 | private ctrl: J.Util.Ctrl;
35 |
36 | private _onDidChangeCodeLenses: vscode.EventEmitter = new vscode.EventEmitter();
37 |
38 |
39 |
40 | constructor(ctrl: J.Util.Ctrl) {
41 | this.ctrl = ctrl;
42 |
43 | vscode.workspace.onDidChangeConfiguration((_) => {
44 | this._onDidChangeCodeLenses.fire();
45 | });
46 | }
47 |
48 | async getRegex() : Promise {
49 | let template = await this.ctrl.config.getTaskInlineTemplate();
50 | return new RegExp(template.after);
51 | }
52 |
53 | public async provideCodeLenses(document: vscode.TextDocument, token: vscode.CancellationToken): Promise {
54 | this.codeLenses = [];
55 | const regex = await this.getRegex();
56 | const text = document.getText();
57 | const matches = regex.exec(text);
58 |
59 | if(matches !== null) {
60 | const line = document.lineAt(document.positionAt(matches.index).line);
61 | const indexOf = line.text.indexOf(matches[0]);
62 | const position = new vscode.Position(line.lineNumber, indexOf);
63 | const range = document.getWordRangeAtPosition(position, regex);
64 | if (range) {
65 | this.codeLenses.push(new vscode.CodeLens(range));
66 | }
67 | }
68 |
69 | return this.codeLenses;
70 | }
71 |
72 | public resolveCodeLens?(codeLens: vscode.CodeLens, token: vscode.CancellationToken):
73 | vscode.CodeLens | Thenable {
74 |
75 |
76 | codeLens.command = {
77 | title: "Collect all tasks",
78 | tooltip: "Collect and modify tasks from this and previous journal entries",
79 | command: "codelens-sample.codelensAction",
80 | arguments: ["Argument 1", false]
81 | };
82 | return codeLens;
83 | }
84 | }
--------------------------------------------------------------------------------
/src/provider/codelens/shift-task.ts:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2021 Patrick Maué
2 | //
3 | // This file is part of vscode-journal.
4 | //
5 | // vscode-journal is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // vscode-journal is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with vscode-journal. If not, see .
17 | //
18 | 'use strict';
19 |
20 | import * as vscode from 'vscode';
21 | import * as J from '../..';
22 |
23 |
24 | export class ShiftTaskCodeLens implements vscode.CodeLensProvider {
25 | private codeLenses: vscode.CodeLens[] = [];
26 | private ctrl: J.Util.Ctrl;
27 |
28 | private _onDidChangeCodeLenses: vscode.EventEmitter = new vscode.EventEmitter();
29 |
30 |
31 |
32 | constructor(ctrl: J.Util.Ctrl) {
33 | this.ctrl = ctrl;
34 |
35 | vscode.workspace.onDidChangeConfiguration((_) => {
36 | this._onDidChangeCodeLenses.fire();
37 | });
38 | }
39 |
40 | async getRegex() : Promise {
41 | let template = await this.ctrl.config.getTaskInlineTemplate();
42 | return new RegExp(template.after);
43 | }
44 |
45 | public async provideCodeLenses(document: vscode.TextDocument, token: vscode.CancellationToken): Promise {
46 | this.codeLenses = [];
47 | const regex = await this.getRegex();
48 | const text = document.getText();
49 | const matches = regex.exec(text);
50 |
51 | if(matches !== null) {
52 | const line = document.lineAt(document.positionAt(matches.index).line);
53 | const indexOf = line.text.indexOf(matches[0]);
54 | const position = new vscode.Position(line.lineNumber, indexOf);
55 | const range = document.getWordRangeAtPosition(position, regex);
56 | if (range) {
57 | this.codeLenses.push(new vscode.CodeLens(range));
58 | }
59 | }
60 |
61 | return this.codeLenses;
62 | }
63 |
64 | public resolveCodeLens?(codeLens: vscode.CodeLens, token: vscode.CancellationToken):
65 | vscode.CodeLens | Thenable {
66 |
67 |
68 | codeLens.command = {
69 | title: "Collect all tasks",
70 | tooltip: "Collect and modify tasks from this and previous journal entries",
71 | command: "codelens-sample.codelensAction",
72 | arguments: ["Argument 1", false]
73 | };
74 | return codeLens;
75 | }
76 | }
--------------------------------------------------------------------------------
/src/provider/commands/copy-task.ts:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2021 Patrick Maué
2 | //
3 | // This file is part of vscode-journal.
4 | //
5 | // vscode-journal is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // vscode-journal is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with vscode-journal. If not, see .
17 | //
18 | 'use strict';
19 |
20 | import moment = require('moment');
21 | import * as vscode from 'vscode';
22 | import * as J from '../..';
23 |
24 | export enum ShiftTarget {
25 | nextWorkingDay,
26 | tomorrow,
27 | today,
28 | successorDay // the day after the currently active entries date (independent from current date)
29 | }
30 |
31 | /**
32 | * The shift task command is active for open tasks, e.g. '-[ ] some text' and triggered by the codeaction in complete-task
33 | *
34 | * Once activated, it will
35 | * - shift the task to the next working day: '-[ ] some text' -> '-[>] some text'
36 | * - annotate the task with link to new entry: '-[>] some text (copied to [../13.md](2021-05-13))'
37 | * - insert the task to the entry of the new date: '-[ ] some text (copied from [../12.md](2021-05-12))'
38 | */
39 |
40 | export class CopyTaskCommand implements vscode.Command {
41 | title: string = "Copy selected task";
42 | command: string = "journal.commands.copy-task";
43 |
44 |
45 | protected constructor(public ctrl: J.Util.Ctrl) { }
46 |
47 | public async dispose(): Promise {
48 | // do nothing
49 | }
50 |
51 | public static create(ctrl: J.Util.Ctrl): vscode.Disposable {
52 | const cmd = new this(ctrl);
53 | vscode.commands.registerCommand(cmd.command, (document, range, target) => cmd.execute(document, range, target));
54 | return cmd;
55 | }
56 |
57 | public async execute(document: vscode.TextDocument, text: string, target: ShiftTarget) {
58 | this.ctrl.logger.trace("command called with ", document.uri, ", text ", text, " and target ", target);
59 |
60 | switch (target) {
61 | case ShiftTarget.nextWorkingDay: return this.insertTaskInNextWorkdDaysEntry(document, text);
62 | case ShiftTarget.today: return this.insertTaskToTodaysEntry(text);
63 | case ShiftTarget.tomorrow: return this.insertTaskToTomorrowsEntry(text);
64 | }
65 | }
66 |
67 | private async insertTaskInNextWorkdDaysEntry(document: vscode.TextDocument, taskString: string) {
68 | // const entryDate: Date = await J.Util.getDateFromURIAndConfig(document.uri.toString(), this.ctrl.config);
69 | const entryMoment = moment();
70 |
71 | let dayIncrement = 1;
72 |
73 | if (entryMoment.day() === 5) {
74 | dayIncrement = 3;
75 | } else if (entryMoment.day() === 6) {
76 | dayIncrement = 2;
77 | }
78 |
79 | this.insertTaskToEntry(taskString, entryMoment.add(dayIncrement, "d").toDate());
80 | }
81 |
82 | private async insertTaskToTomorrowsEntry(taskString: string) {
83 | this.insertTaskToEntry(taskString, moment().add(1, 'd').toDate());
84 | }
85 |
86 | private async insertTaskToTodaysEntry(taskString: string) {
87 | this.insertTaskToEntry(taskString, moment().toDate());
88 | }
89 |
90 | private async insertTaskToEntry(taskString: string, date: Date) {
91 | const doc : vscode.TextDocument = await this.ctrl.reader.loadEntryForDay(date);
92 | const tpl : J.Model.InlineTemplate = await this.ctrl.config.getTaskInlineTemplate();
93 | const pos = this.ctrl.inject.computePositionForInput(doc, tpl);
94 | const inlineString: J.Model.InlineString = await this.ctrl.inject.buildInlineString(doc, tpl, ["${input}", taskString]);
95 | this.ctrl.inject.injectInlineString(inlineString);
96 |
97 | doc.save();
98 | }
99 |
100 |
101 |
102 | }
--------------------------------------------------------------------------------
/src/provider/commands/index.ts:
--------------------------------------------------------------------------------
1 | export { CopyTaskCommand as ShiftTaskCommand } from './copy-task';
2 | export { OpenJournalWorkspaceCommand } from './open-journal-workspace';
3 | export { PrintTimeCommand } from './print-current-time';
4 | export { PrintDurationCommand } from './print-duration-between-selected-times';
5 | export { PrintSumCommand } from './print-sum-of-selected-numbers';
6 | export { ShowEntryForInputCommand } from './show-entry-for-input';
7 | export { ShowEntryForTodayCommand } from './show-entry-for-today';
8 | export { ShowEntryForTomorrowCommand } from './show-entry-for-tomorrow';
9 | export { ShowEntryForYesterdayCommand } from './show-entry-for-yesterday';
10 | export { ShowNoteCommand } from './show-note';
11 | export { InsertMemoCommand } from './insert-memo';
--------------------------------------------------------------------------------
/src/provider/commands/insert-memo.ts:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2021 Patrick Maué
2 | //
3 | // This file is part of vscode-journal.
4 | //
5 | // vscode-journal is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // vscode-journal is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with vscode-journal. If not, see .
17 | //
18 | 'use strict';
19 |
20 | import * as vscode from 'vscode';
21 | import * as J from '../..';
22 | import { AbstractLoadEntryForDateCommand } from './show-entry-for-date';
23 |
24 | /**
25 | * Legacy command, same functionality as ShowEntryForInputCommand
26 | * @deprecated
27 | */
28 |
29 | export class InsertMemoCommand extends AbstractLoadEntryForDateCommand {
30 | title: string = "Insert Memo";
31 | command: string = "journal.memo";
32 |
33 | public static create(ctrl: J.Util.Ctrl): vscode.Disposable {
34 | const cmd = new this(ctrl);
35 | vscode.commands.registerCommand(cmd.command, () => cmd.execute());
36 | return cmd;
37 | }
38 |
39 | /**
40 | * Opens the editor for a specific day. Supported values are explicit dates (in ISO format),
41 | * offsets (+ or - as prefix and 0) and weekdays (next wednesday)
42 | *
43 | * Update: supports much more now
44 | */
45 | public async execute(): Promise {
46 | this.ctrl.logger.trace("Executing command: ", this.command);
47 |
48 | const input: J.Model.Input = await this.ctrl.ui.getUserInputWithValidation();
49 | super.execute(input);
50 | }
51 |
52 |
53 |
54 |
55 | }
--------------------------------------------------------------------------------
/src/provider/commands/open-journal-workspace.ts:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2021 Patrick Maué
2 | //
3 | // This file is part of vscode-journal.
4 | //
5 | // vscode-journal is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // vscode-journal is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with vscode-journal. If not, see .
17 | //
18 | 'use strict';
19 |
20 | import * as vscode from 'vscode';
21 | import * as J from '../..';
22 |
23 |
24 | export class OpenJournalWorkspaceCommand implements vscode.Command, vscode.Disposable {
25 | title: string = 'Open the journal workspace';
26 | command: string = 'journal.open';
27 |
28 |
29 | protected constructor(public ctrl: J.Util.Ctrl) {}
30 |
31 | public async dispose(): Promise {
32 | // do nothing
33 | }
34 |
35 | public static create(ctrl: J.Util.Ctrl): vscode.Disposable {
36 | const cmd = new this(ctrl);
37 | vscode.commands.registerCommand(cmd.command, () => cmd.openWorkspace());
38 | return cmd;
39 |
40 | }
41 |
42 | /**
43 | * Called by command 'Journal:open'. Opens a new windows with the Journal base directory as root.
44 | *
45 | * @returns {Q.Promise}
46 | * @memberof JournalCommands
47 | */
48 | public async openWorkspace(): Promise {
49 | this.ctrl.logger.trace("Executing command: ", this.command);
50 |
51 | let path = vscode.Uri.file(this.ctrl.config.getBasePath());
52 |
53 | try {
54 | vscode.commands.executeCommand('vscode.openFolder', path, true);
55 | } catch (error) {
56 | this.ctrl.logger.error("Failed to execute command: ", this.command, "Reason: ", error);
57 | this.ctrl.ui.showError("Failed to open the journal workspace.");
58 | }
59 | }
60 |
61 | }
--------------------------------------------------------------------------------
/src/provider/commands/print-current-time.ts:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2021 Patrick Maué
2 | //
3 | // This file is part of vscode-journal.
4 | //
5 | // vscode-journal is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // vscode-journal is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with vscode-journal. If not, see .
17 | //
18 | 'use strict';
19 |
20 | import * as vscode from 'vscode';
21 | import * as J from '../..';
22 |
23 |
24 | export class PrintTimeCommand implements vscode.Command, vscode.Disposable {
25 | title: string = "Print current time";
26 | command: string = "journal.printTime";
27 |
28 | protected constructor(public ctrl: J.Util.Ctrl) {}
29 |
30 | public async dispose(): Promise {
31 | // do nothing
32 | }
33 |
34 | public static create(ctrl: J.Util.Ctrl): vscode.Disposable {
35 | const cmd = new this(ctrl);
36 | vscode.commands.registerCommand(cmd.command, () => cmd.printTime());
37 | return cmd;
38 | }
39 |
40 | /**
41 | * Prints the current time at the cursor postion
42 | */
43 | public async printTime(): Promise {
44 | this.ctrl.logger.trace("Executing command: ", this.command);
45 |
46 | try {
47 | let editor: vscode.TextEditor = vscode.window.activeTextEditor;
48 |
49 | // Todo: identify scope of the active editot
50 | let template: J.Model.ScopedTemplate = await this.ctrl.config.getTimeStringTemplate();
51 |
52 | let currentPosition: vscode.Position = editor.selection.active;
53 |
54 | this.ctrl.inject.injectString(editor.document, template.value!, currentPosition);
55 |
56 | } catch (error) {
57 | this.ctrl.logger.error("Failed to execute command: ", this.command, "Reason: ", error);
58 | this.ctrl.ui.showError("Failed to print current time.");
59 | }
60 | }
61 |
62 |
63 |
64 | }
--------------------------------------------------------------------------------
/src/provider/commands/print-duration-between-selected-times.ts:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2021 Patrick Maué
2 | //
3 | // This file is part of vscode-journal.
4 | //
5 | // vscode-journal is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // vscode-journal is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with vscode-journal. If not, see .
17 | //
18 | 'use strict';
19 |
20 | import moment = require('moment');
21 | import * as vscode from 'vscode';
22 | import * as J from '../..';
23 |
24 |
25 | export class PrintDurationCommand implements vscode.Command, vscode.Disposable {
26 | title: string = "Print duration between two selected times";
27 | command: string = "journal.printDuration";
28 |
29 | protected constructor(public ctrl: J.Util.Ctrl) {}
30 |
31 | public async dispose(): Promise {
32 | // do nothing
33 | }
34 |
35 | public static create(ctrl: J.Util.Ctrl): vscode.Disposable {
36 | const cmd = new this(ctrl);
37 | vscode.commands.registerCommand(cmd.command, () => cmd.printDuration());
38 | return cmd;
39 | }
40 |
41 | /**
42 | * Called by command 'Journal:printDuration'. Requires three selections (three active cursors)
43 | * in current document. It identifies which of the selections are times (in the format hh:mm
44 | * or glued like "1223") and where to print the duration (in decimal form).
45 | * For now the duration is always printing hours.
46 | */
47 | public async printDuration() {
48 | this.ctrl.logger.trace("Executing command: ", this.command);
49 |
50 |
51 | try {
52 | let editor: vscode.TextEditor = vscode.window.activeTextEditor;
53 | let regExp: RegExp = /\d{1,2}:?\d{0,2}(?:\s?(?:am|AM|pm|PM))?|\s/;
54 | // let regExp: RegExp = /(\d{1,2}:?\d{2}\s)|(\d{1,4}\s?(?:am|pm)\s)|(\d{1,2}[,\.]\d{1,2}\s)|(\s)/;
55 |
56 | if (editor.selections.length !== 3) {
57 | throw new Error("To compute the duration, you have to select two times in your text as well as the location where to print it. ");
58 | }
59 |
60 | //
61 | let start: moment.Moment | undefined;
62 | let end: moment.Moment | undefined;
63 | let target: vscode.Position | undefined;
64 |
65 |
66 | editor.selections.forEach((selection: vscode.Selection) => {
67 | let range: vscode.Range | undefined = editor.document.getWordRangeAtPosition(selection.active, regExp);
68 |
69 |
70 | if (J.Util.isNullOrUndefined(range)) {
71 | target = selection.active;
72 | return;
73 | }
74 |
75 | let text = editor.document.getText(range);
76 |
77 | // check if empty string
78 | if (text.trim().length === 0) {
79 | target = selection.active;
80 | return;
81 | }
82 |
83 | // try to format into local date
84 | let time: moment.Moment = moment(text, "LT");
85 |
86 | if (!time.isValid()) {
87 | // 123pm
88 | let mod: number = text.search(/am|pm/);
89 | if (mod > 0) {
90 | if (text.charAt(mod - 1) !== " ") {
91 | text = text.substr(0, mod - 1) + " " + text.substr(mod);
92 | }
93 | time = moment(text, "hmm a");
94 | }
95 | }
96 |
97 | if (!time.isValid()) {
98 | // 123AM
99 | let mod: number = text.search(/AM|PM/);
100 | if (mod > 0) {
101 | if (text.charAt(mod - 1) !== " ") {
102 | text = text.substring(0, mod - 1) + " " + text.substr(mod);
103 | }
104 | time = moment(text, "hmm A");
105 | }
106 | }
107 |
108 | if (!time.isValid()) {
109 | // 2330
110 | time = moment(text, "Hmm");
111 | }
112 |
113 | // parsing glued hours
114 | if (J.Util.isNullOrUndefined(start)) {
115 | start = time;
116 | } else if (start!.isAfter(time)) {
117 | end = start;
118 | start = time;
119 | } else {
120 | end = time;
121 | }
122 | });
123 |
124 | if (J.Util.isNullOrUndefined(start)) { throw new Error("No valid start time selected"); } // tslint:disable-line
125 | else if (J.Util.isNullOrUndefined(end)) { throw new Error("No valid end time selected"); } // tslint:disable-line
126 | else if (J.Util.isNullOrUndefined(target)) { throw new Error("No valid target selected for printing the duration."); } // tslint:disable-line
127 | else {
128 | let duration = moment.duration(start!.diff(end!));
129 | let formattedDuration = Math.abs(duration.asHours()).toFixed(2);
130 | this.ctrl.inject.injectString(editor.document, formattedDuration, target!);
131 | }
132 |
133 |
134 | } catch (error) {
135 | this.ctrl.logger.error("Failed to execute command: ", this.command, "Reason: ", error);
136 | this.ctrl.ui.showError("Failed to print duration.");
137 | }
138 |
139 | }
140 |
141 | }
--------------------------------------------------------------------------------
/src/provider/commands/print-sum-of-selected-numbers.ts:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2021 Patrick Maué
2 | //
3 | // This file is part of vscode-journal.
4 | //
5 | // vscode-journal is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // vscode-journal is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with vscode-journal. If not, see .
17 | //
18 | 'use strict';
19 |
20 | import * as vscode from 'vscode';
21 | import * as J from '../..';
22 |
23 |
24 | export class PrintSumCommand implements vscode.Command, vscode.Disposable {
25 | title: string = "Print sum of two selected numbers";
26 | command: string = "journal.printSum";
27 |
28 | protected constructor(public ctrl: J.Util.Ctrl) {}
29 |
30 | public async dispose(): Promise {
31 | // do nothing
32 | }
33 |
34 | public static create(ctrl: J.Util.Ctrl): vscode.Disposable {
35 | const cmd = new this(ctrl);
36 | vscode.commands.registerCommand(cmd.command, () => cmd.execute());
37 | return cmd;
38 | }
39 | /**
40 | * Prints the sum of the selected numbers in the current editor at the selection location
41 | */
42 | public async execute(): Promise {
43 | this.ctrl.logger.trace("Executing command: ", this.command);
44 |
45 |
46 | try {
47 | let editor: vscode.TextEditor = vscode.window.activeTextEditor;
48 | let regExp: RegExp = /(\d+[,\.]?\d*\s?)|(\s)/;
49 |
50 | let target: vscode.Position;
51 | let numbers: number[] = [];
52 |
53 | editor.selections.forEach((selection: vscode.Selection) => {
54 | let range: vscode.Range | undefined = editor.document.getWordRangeAtPosition(selection.active, regExp);
55 |
56 | if (J.Util.isNullOrUndefined(range)) {
57 | target = selection.active;
58 | return;
59 | }
60 |
61 | let text = editor.document.getText(range);
62 |
63 | // check if empty string
64 | if (text.trim().length === 0) {
65 | target = selection.active;
66 |
67 | return;
68 | }
69 | // check if number
70 | let number: number = Number(text);
71 | if (number > 0) {
72 | numbers.push(number);
73 | return;
74 | }
75 |
76 | });
77 |
78 | if (numbers.length < 2) { throw Error("You have to select at least two numbers"); } // tslint:disable-line
79 | else if (J.Util.isNullOrUndefined(target!)) { throw Error("No valid target selected for printing the sum."); } // tslint:disable-line
80 | else {
81 | let result: string = numbers.reduce((previous, current) => previous + current).toString();
82 | this.ctrl.inject.injectString(editor.document, result + "", target!);
83 | }
84 | } catch (error) {
85 | this.ctrl.logger.error("Failed to execute command: ", this.command, "Reason: ", error);
86 | this.ctrl.ui.showError("Failed to print sum of selected numbers.");
87 | }
88 |
89 | }
90 |
91 | }
--------------------------------------------------------------------------------
/src/provider/commands/show-entry-for-date.ts:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2021 Patrick Maué
2 | //
3 | // This file is part of vscode-journal.
4 | //
5 | // vscode-journal is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // vscode-journal is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with vscode-journal. If not, see .
17 | //
18 | 'use strict';
19 |
20 | import * as vscode from 'vscode';
21 | import * as J from '../..';
22 | import { NoteInput, SelectedInput } from '../../model';
23 |
24 |
25 | export class AbstractLoadEntryForDateCommand implements vscode.Disposable {
26 |
27 | protected constructor(public ctrl: J.Util.Ctrl) { }
28 |
29 | public async dispose(): Promise {
30 | // do nothing
31 | }
32 |
33 | /**
34 | * Implements commands "yesterday", "today", "yesterday", where the input is predefined (no input box appears)
35 | * @param offset
36 | */
37 | public async execute(input: J.Model.Input ): Promise {
38 |
39 | try {
40 | const doc = await this.loadPageForInput(input);
41 | await this.ctrl.ui.showDocument(doc);
42 | } catch (error) {
43 | if (error !== 'cancel') {
44 | this.ctrl.logger.error("Failed to load entry for input: ", input.text, "Reason: ", error);
45 | this.ctrl.ui.showError("Failed to open entry.");
46 | } else {return;}
47 | }
48 | }
49 |
50 |
51 |
52 | /**
53 | * Expects any user input from the magic input and either opens the file or creates it.
54 | * @param input
55 | */
56 | protected async loadPageForInput(input: J.Model.Input): Promise {
57 |
58 | if (input instanceof SelectedInput) {
59 | // we just load the path
60 | return this.ctrl.ui.openDocument((input).path);
61 | } if (input instanceof NoteInput) {
62 | // we create or load the notes
63 | return new J.Provider.LoadNotes(input, this.ctrl).loadWithPath(input.path);
64 |
65 | } else {
66 | return this.ctrl.reader.loadEntryForInput(input)
67 | .then((doc: vscode.TextDocument) => this.ctrl.inject.injectInput(doc, input));
68 | }
69 | }
70 | }
--------------------------------------------------------------------------------
/src/provider/commands/show-entry-for-input.ts:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2021 Patrick Maué
2 | //
3 | // This file is part of vscode-journal.
4 | //
5 | // vscode-journal is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // vscode-journal is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with vscode-journal. If not, see .
17 | //
18 | 'use strict';
19 |
20 | import * as vscode from 'vscode';
21 | import * as J from '../..';
22 | import { AbstractLoadEntryForDateCommand } from './show-entry-for-date';
23 |
24 |
25 | export class ShowEntryForInputCommand extends AbstractLoadEntryForDateCommand {
26 | title: string = "Show journal entry for given user input";
27 | command: string = "journal.day";
28 |
29 | public static create(ctrl: J.Util.Ctrl): vscode.Disposable {
30 | const cmd = new this(ctrl);
31 | vscode.commands.registerCommand(cmd.command, () => cmd.execute());
32 | return cmd;
33 | }
34 |
35 | /**
36 | * Opens the editor for a specific day. Supported values are explicit dates (in ISO format),
37 | * offsets (+ or - as prefix and 0) and weekdays (next wednesday)
38 | *
39 | * Update: supports much more now
40 | */
41 | public async execute(): Promise {
42 | this.ctrl.logger.trace("Executing command: ", this.command);
43 |
44 | const input: J.Model.Input = await this.ctrl.ui.getUserInputWithValidation();
45 | super.execute(input);
46 | }
47 |
48 |
49 |
50 |
51 | }
--------------------------------------------------------------------------------
/src/provider/commands/show-entry-for-today.ts:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2021 Patrick Maué
2 | //
3 | // This file is part of vscode-journal.
4 | //
5 | // vscode-journal is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // vscode-journal is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with vscode-journal. If not, see .
17 | //
18 | 'use strict';
19 |
20 | import * as vscode from 'vscode';
21 | import * as J from '../..';
22 | import { AbstractLoadEntryForDateCommand } from './show-entry-for-date';
23 |
24 |
25 | export class ShowEntryForTodayCommand extends AbstractLoadEntryForDateCommand {
26 | title: string = "Show journal entry for today";
27 | command: string = "journal.today";
28 |
29 |
30 | public static create(ctrl: J.Util.Ctrl): vscode.Disposable {
31 | const cmd = new this(ctrl);
32 |
33 | let input = new J.Model.Input();
34 | input.offset = 0;
35 |
36 | vscode.commands.registerCommand(cmd.command, () => cmd.execute(input));
37 | return cmd;
38 | }
39 |
40 | }
--------------------------------------------------------------------------------
/src/provider/commands/show-entry-for-tomorrow.ts:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2021 Patrick Maué
2 | //
3 | // This file is part of vscode-journal.
4 | //
5 | // vscode-journal is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // vscode-journal is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with vscode-journal. If not, see .
17 | //
18 | 'use strict';
19 |
20 | import * as vscode from 'vscode';
21 | import * as J from '../..';
22 | import { AbstractLoadEntryForDateCommand } from './show-entry-for-date';
23 |
24 |
25 | export class ShowEntryForTomorrowCommand extends AbstractLoadEntryForDateCommand {
26 | title: string = "Show journal entry for tomorrow";
27 | command: string = "journal.tomorrow";
28 |
29 |
30 | public static create(ctrl: J.Util.Ctrl): vscode.Disposable {
31 | const cmd = new this(ctrl);
32 |
33 | let input = new J.Model.Input();
34 | input.offset = 1;
35 |
36 | vscode.commands.registerCommand(cmd.command, () => cmd.execute(input));
37 | return cmd;
38 | }
39 | }
--------------------------------------------------------------------------------
/src/provider/commands/show-entry-for-yesterday.ts:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2021 Patrick Maué
2 | //
3 | // This file is part of vscode-journal.
4 | //
5 | // vscode-journal is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // vscode-journal is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with vscode-journal. If not, see .
17 | //
18 | 'use strict';
19 |
20 | import * as vscode from 'vscode';
21 | import * as J from '../..';
22 | import { AbstractLoadEntryForDateCommand } from './show-entry-for-date';
23 |
24 |
25 | export class ShowEntryForYesterdayCommand extends AbstractLoadEntryForDateCommand{
26 | title: string = "Show journal entry for yesterday";
27 | command: string = "journal.yesterday";
28 |
29 |
30 | public static create(ctrl: J.Util.Ctrl): vscode.Disposable {
31 | const cmd = new this(ctrl);
32 |
33 | let input = new J.Model.Input();
34 | input.offset = -1;
35 |
36 | vscode.commands.registerCommand(cmd.command, () => cmd.execute(input));
37 | return cmd;
38 | }
39 | }
--------------------------------------------------------------------------------
/src/provider/commands/show-note.ts:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2021 Patrick Maué
2 | //
3 | // This file is part of vscode-journal.
4 | //
5 | // vscode-journal is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // vscode-journal is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with vscode-journal. If not, see .
17 | //
18 | 'use strict';
19 |
20 | import * as vscode from 'vscode';
21 | import * as J from '../..';
22 |
23 |
24 | export class ShowNoteCommand implements vscode.Command, vscode.Disposable {
25 | title: string = 'Loads and shows editor for new note';
26 | command: string = 'journal.note';
27 |
28 |
29 | protected constructor(public ctrl: J.Util.Ctrl) { }
30 |
31 | public async dispose(): Promise {
32 | // do nothing
33 | }
34 |
35 | public static create(ctrl: J.Util.Ctrl): vscode.Disposable {
36 | const cmd = new this(ctrl);
37 | vscode.commands.registerCommand(cmd.command, () => cmd.execute());
38 | return cmd;
39 | }
40 |
41 | /**
42 | * Creates a new file for a note following the configured pattern
43 | * Shows the file to let the user start adding notes right away.
44 | */
45 | public async execute(): Promise {
46 |
47 | this.ctrl.logger.trace("Executing command: ", this.command);
48 |
49 | try {
50 | const userInput: string = await this.ctrl.ui.getUserInput("Enter title for new note");
51 | let parsedInput: J.Model.Input = await this.ctrl.parser.parseInput(userInput);
52 |
53 | const doc : vscode.TextDocument = await new J.Provider.LoadNotes(parsedInput, this.ctrl).load();
54 | await this.ctrl.ui.showDocument(doc);
55 |
56 |
57 | } catch (error) {
58 | this.ctrl.logger.error("Failed to execute command: ", this.command, "Reason: ", error);
59 | this.ctrl.ui.showError("Failed to load note.");
60 | }
61 | }
62 |
63 |
64 | }
--------------------------------------------------------------------------------
/src/provider/features/load-note.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import * as J from '../..';
3 |
4 | /**
5 | * Feature responsible for creating (if needed) and loading notes given a user input as title.
6 | * (extracted as feature to enable direct unit tests)
7 | */
8 |
9 | export class LoadNotes {
10 |
11 | constructor(public input: J.Model.Input, public ctrl: J.Util.Ctrl) {
12 |
13 | }
14 |
15 | public async load(): Promise {
16 | let path = await this.ctrl.parser.resolveNotePathForInput(this.input);
17 | return this.loadWithPath(path);
18 | }
19 |
20 |
21 | public async loadWithPath(path: string): Promise {
22 |
23 | let content: string = await this.ctrl.inject.formatNote(this.input);
24 |
25 | let document : vscode.TextDocument = await this.loadNote(path, content);
26 |
27 | // inject reference to new note in today's journal page
28 | await this.ctrl.reader.loadEntryForInput(new J.Model.Input(0)) // triggered automatically by loading today's page (we don't show it though)
29 | .catch(reason => this.ctrl.logger.error("Failed to load today's page for injecting link to note.", reason));
30 |
31 | return document;
32 | }
33 |
34 | /**
35 | * Creates or loads a note
36 | *
37 | * @param {string} path
38 | * @param {string} content
39 | * @returns {Promise}
40 | * @memberof Writer
41 | */
42 | public async loadNote(path: string, content: string): Promise {
43 | this.ctrl.logger.trace("Entering loadNote() in features/load-note.ts for path: ", path);
44 |
45 | return new Promise((resolve, reject) => {
46 | // check if file exists already
47 |
48 | this.ctrl.ui.openDocument(path)
49 | .then((doc: vscode.TextDocument) => resolve(doc))
50 | .catch(error => {
51 | this.ctrl.writer.createSaveLoadTextDocument(path, content)
52 | .then((doc: vscode.TextDocument) => resolve(doc))
53 | .catch(error => {
54 | this.ctrl.logger.error(error);
55 | reject("Failed to load note.");
56 | });
57 | });
58 |
59 | });
60 | }
61 |
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/src/provider/features/show-pick-list.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import * as J from '../..';
3 |
4 | /**
5 | * Feature responsible for scanning the journal and notes folders and collecting the items displayed in the picklist
6 | */
7 |
8 | export class ShowPickLists {
9 | }
--------------------------------------------------------------------------------
/src/provider/index.d.ts:
--------------------------------------------------------------------------------
1 | export { InputMatcher } from "./InputMatcher";
2 |
--------------------------------------------------------------------------------
/src/provider/index.ts:
--------------------------------------------------------------------------------
1 | export { MatchInput } from "./features/match-input";
2 | export { SyncNoteLinks } from "./features/sync-note-links";
3 | export { LoadNotes } from "./features/load-note";
4 | export { ScanEntries, sortPickEntries } from "./features/scan-entries";
5 |
6 | export * as Commands from './commands';
7 |
8 | export { MigrateTasksCodeLens } from './codelens/migrate-tasks';
9 | export { ShiftTaskCodeLens } from './codelens/shift-task';
10 |
11 | export { CompletedTaskActions } from './codeactions/for-completed-tasks';
12 | export { OpenTaskActions } from './codeactions/for-open-tasks';
13 |
14 |
--------------------------------------------------------------------------------
/src/test/Readme.md:
--------------------------------------------------------------------------------
1 | # How to run the direct tests
2 |
3 | npx ts-node ./test/direct.ts
--------------------------------------------------------------------------------
/src/test/TestLogger.d.ts:
--------------------------------------------------------------------------------
1 | import { Logger } from "../util/logger";
2 | export declare class TestLogger implements Logger {
3 | error(message: string, ...optionalParams: any[]): void;
4 | printError(error: Error): void;
5 | showChannel(): void;
6 | debug(message: string, ...optionalParams: any[]): void;
7 | trace(message: string, ...optionalParams: any[]): void;
8 | }
9 |
--------------------------------------------------------------------------------
/src/test/TestLogger.ts:
--------------------------------------------------------------------------------
1 | import { Logger } from "../util/logger";
2 |
3 | export class TestLogger implements Logger {
4 | constructor(public tracing: boolean) {
5 |
6 | }
7 |
8 | error(message: string, ...optionalParams: any[]): void {
9 | console.error("ERROR", message, ...optionalParams);
10 | }
11 | printError(error: Error): void {
12 | throw new Error("Method not implemented.");
13 | }
14 | showChannel(): void {
15 | throw new Error("Method not implemented.");
16 | }
17 | debug(message: string, ...optionalParams: any[]): void {
18 | console.debug("DEBUG", message, ...optionalParams);
19 | }
20 | trace(message: string, ...optionalParams: any[]): void {
21 | if(this.tracing) {
22 | console.trace(message, ...optionalParams);
23 | }
24 | // do nothing
25 |
26 | }
27 |
28 | }
--------------------------------------------------------------------------------
/src/test/direct/direct.d.ts:
--------------------------------------------------------------------------------
1 | import { ScopedTemplate } from "../../ext/index";
2 | export declare function replaceDateFormats(st: ScopedTemplate, date: Date): void;
3 |
--------------------------------------------------------------------------------
/src/test/direct/direct.ts:
--------------------------------------------------------------------------------
1 |
2 | import moment = require("moment");
3 | import { ScopedTemplate } from "../../model";
4 |
5 |
6 | let regExpDateFormats: RegExp = new RegExp(/\$\{(?:(year|month|day|localTime|localDate)|(d:\w+))\}/g);
7 | export function replaceDateFormats(st: ScopedTemplate, date: Date): void {
8 | let matches: RegExpMatchArray | null = st.template.match(regExpDateFormats);
9 | if(matches === null) {
10 | return;
11 | }
12 |
13 |
14 | console.log(JSON.stringify(matches));
15 |
16 | if (matches.length === 0) { return; }
17 |
18 | let mom: moment.Moment = moment(date);
19 |
20 | matches.forEach(match => {
21 | switch (match) {
22 | case "${year}":
23 | st.template = st.template.replace(match, mom.format("YYYY"));
24 | break;
25 | case "${month}":
26 | st.template = st.template.replace(match, mom.format("MM"));
27 | break;
28 | case "${day}":
29 | st.template = st.template.replace(match, mom.format("DD"));
30 | break;
31 | case "${localTime}":
32 | st.template = st.template.replace(match, mom.format("LL"));
33 | break;
34 | case "${localDate}":
35 | st.template = st.template.replace(match, mom.format("LD"));
36 | break;
37 | default:
38 | // check if custom format
39 | if(match.startsWith("${d:")) {
40 |
41 | let modifier = match.substring(match.indexOf("d:")+2, match.length-1); // includes } at the end
42 | st.template = st.template.replace(match, mom.format(modifier));
43 | }
44 | break;
45 | }
46 | });
47 |
48 |
49 | }
50 |
51 |
52 |
53 | let t1: ScopedTemplate = {
54 | scope: "default",
55 | template: "${year} and ${day} and some ${month}",
56 | };
57 |
58 | replaceDateFormats(t1, new Date());
59 | console.log(t1.template);
60 |
61 | let t2: ScopedTemplate = {
62 | scope: "default",
63 | template: "Local time ${localTime} and custom format ${d:YY} for year",
64 | };
65 |
66 | replaceDateFormats(t2, new Date());
67 | console.log(t2.template);
--------------------------------------------------------------------------------
/src/test/direct/input_parser.d.ts:
--------------------------------------------------------------------------------
1 | export {};
2 |
--------------------------------------------------------------------------------
/src/test/direct/input_parser.ts:
--------------------------------------------------------------------------------
1 | import { MatchInput } from '../../provider';
2 | import { TestLogger } from '../TestLogger';
3 |
4 | let inputMatcher = new MatchInput(new TestLogger(false), "en-US");
5 |
6 | testExpr1();
7 |
8 | async function testExpr1() {
9 | let str = "next monday";
10 | let input = await inputMatcher.parseInput(str);
11 | console.log(input.flags);
12 |
13 |
14 | }
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/test/direct/path-parse-with-date.ts:
--------------------------------------------------------------------------------
1 | import * as assert from 'assert';
2 | import moment = require('moment');
3 |
4 |
5 |
6 | const regExpDateFormats: RegExp = new RegExp(/\$\{(?:(year|month|day|localTime|localDate|weekday)|(d:[\s\S]+?))\}/g);
7 | let base = "c:\\Users\\user\\Git\\vscode-journal\\test\\workspace\\journal";
8 | let pathTpl = "${base}/${year}-${month}";
9 | let fileTpl = "${year}${month}${day}.${ext}";
10 | let uri = "file:/Users/user/Git/vscode-journal/test/workspace/journal/2020-07/20200709.md";
11 |
12 | console.log("Test to acquire date from uri: ", uri);
13 | getDateFromURI(uri, pathTpl, fileTpl, base)
14 | .then(result => assertCorrectDate(result));
15 |
16 | pathTpl = "${year}/${month}/${day}";
17 | fileTpl = "journal.${ext}";
18 | uri = "file:/Users/user/Git/vscode-journal/test/workspace/journal/2020/07/09/journal.md";
19 | console.log("Test to acquire date from uri: ", uri);
20 | getDateFromURI(uri, pathTpl, fileTpl, base)
21 | .then(result => assertCorrectDate(result));
22 |
23 |
24 | pathTpl = "${base}";
25 | fileTpl = "${year}-${month}-${day}";
26 | uri = "file:/Users/user/Git/vscode-journal/test/workspace/journal/2020-07-09.md";
27 | console.log("Test to acquire date from uri: ", uri);
28 | getDateFromURI(uri, pathTpl, fileTpl, base)
29 | .then(result => assertCorrectDate(result));
30 |
31 | pathTpl = "${base}";
32 | fileTpl = "${d:YYYY-MM-DD}";
33 | uri = "file:/Users/user/Git/vscode-journal/test/workspace/journal/2020-07-09.md";
34 | console.log("Test to acquire date from uri: ", uri);
35 | getDateFromURI(uri, pathTpl, fileTpl, base)
36 | .then(result => assertCorrectDate(result));
37 |
38 | export async function getDateFromURI(uri: string, pathTemplate: string, fileTemplate: string, basePath: string) {
39 | if(fileTemplate.indexOf(".") > 0) {fileTemplate = fileTemplate.substr(0, fileTemplate.lastIndexOf("."));}
40 | if(pathTemplate.startsWith("${base}/")) {pathTemplate = pathTemplate.substring("${base}/".length);}
41 |
42 | let year: number | undefined;
43 | let month: number | undefined;
44 | let day: number | undefined;
45 |
46 | // input template is something like
47 | // "path": "${base}/${year}/${month}", -> sdlkjfwejf/2021/12
48 | // "file": "${day}.${ext}" -> 21.md
49 | // but also file: ${year}-${month}-${day}.md
50 |
51 |
52 | // go through each element in path and assign it to a date part or skip it
53 | let pathParts = uri.split("/");
54 |
55 |
56 | // check if part is in base path (if yes, we ignore)
57 | // for the rest: last part is file, everything else path pattern
58 | let pathElements: string[] = [];
59 | let pathStr: string = "";
60 | let fileStr = "";
61 |
62 | pathParts.forEach((element, index) => {
63 | if(element.trim().length === 0) {return;}
64 | else if(element.startsWith("file:")) {return;}
65 | else if(basePath.search(element) >= 0) {return;}
66 | else if(index+1 === pathParts.length) {fileStr = element.substr(0, element.lastIndexOf("."));}
67 | else {
68 | pathElements.concat(element);
69 | if(pathStr.length > 1) {pathStr += "/";}
70 | pathStr += element;
71 | }
72 | });
73 |
74 |
75 | console.log(pathStr);
76 | console.log(fileStr);
77 |
78 | // ${base}/${year}/${month}-${day}/${LD}.${ext}
79 | // remove base and ext variables
80 | // tokenize in variables and loop through matches.
81 | // replace each match with momemnt format and call moment.parse
82 |
83 | // path: 2021-08
84 | // file: 2021-08-12.md
85 |
86 | // handle path segment (we just compare indicies)
87 | /*
88 | pathTpl.split("/").forEach((element, index) => {
89 |
90 | if(element.match("")
91 | })*/
92 | let mom: moment.Moment = moment(fileStr, fileTemplate);
93 |
94 | const entryMomentTpl = replaceDateTemplatesWithMomentsFormats(fileTemplate);
95 | const pathMomentTpl = replaceDateTemplatesWithMomentsFormats(pathTemplate);
96 |
97 | // filestr: "20210809"
98 | // path str: "/202108"
99 | // path tpl: ${year}-${month}"
100 |
101 | let a = moment(fileStr, entryMomentTpl);
102 | let b = moment(pathStr, pathMomentTpl);
103 |
104 |
105 | console.log("Parsed file string: ", a.format());
106 | console.log("Parsed path string: ", b.format());
107 |
108 | let result = moment();
109 |
110 | // consolidate the two
111 | if(fileTemplate.indexOf("${year}")>=0) {result = result.year(a.year());}
112 | else {result = result.year(b.year());}
113 | if(fileTemplate.indexOf("${month}")>=0) {result = result.month(a.month());}
114 | else {result = result.month(b.month());}
115 | if(fileTemplate.indexOf("${day}")>=0) {result = result.date(a.date());}
116 | else {result = result.date(b.date());}
117 |
118 | return result.toDate();
119 |
120 | }
121 |
122 |
123 |
124 | export function replaceDateTemplatesWithMomentsFormats(template: string): string {
125 | let matches: RegExpMatchArray | null = template.match(regExpDateFormats);
126 | if(matches === null) {
127 | return template;
128 | }
129 |
130 | matches.forEach(match => {
131 | switch (match) {
132 | case "${year}":
133 | template = template.replace(match, "YYYY"); break;
134 | case "${month}":
135 | template = template.replace(match, "MM"); break;
136 | case "${day}":
137 | template = template.replace(match, "DD"); break;
138 | case "${localTime}":
139 | template = template.replace(match, "LT"); break;
140 | case "${localDate}":
141 | template = template.replace(match, "LL"); break;
142 | case "${weekday}":
143 | template = template.replace(match, "dddd"); break;
144 | default:
145 | // check if custom format
146 | if (match.startsWith("${d:")) {
147 |
148 | let modifier = match.substring(match.indexOf("d:") + 2, match.length - 1); // includes } at the end
149 | // st.template = st.template.replace(match, mom.format(modifier));
150 | // fix for #51
151 | template = template.replace(match, modifier);
152 | break;
153 | }
154 | break;
155 | }
156 | });
157 | return template;
158 |
159 | }
160 |
161 | function assertCorrectDate(date: Date): void {
162 | let iso = date.toISOString();
163 | let result = iso.substring(0, iso.indexOf('T'));
164 | console.log("Parsed result is: ", result);
165 | assert.match(result, /2020-07-09/);
166 | }
--------------------------------------------------------------------------------
/src/test/direct/replace-variables-in-string.ts:
--------------------------------------------------------------------------------
1 | import { replaceDateFormats } from "../../util/dates";
2 |
3 |
4 |
5 | let result: string = "no result";
6 | result = replaceDateFormats("${year} and ${day} and some ${month}", new Date());
7 | console.log(result);
8 |
9 | result = replaceDateFormats("Local time ${localTime} and custom format ${d:YY} for year", new Date());
10 | console.log(result);
--------------------------------------------------------------------------------
/src/test/direct/simple-run-command.ts:
--------------------------------------------------------------------------------
1 | const msg: string = 'Hello World';
2 | console.log(msg);
--------------------------------------------------------------------------------
/src/test/runTest.d.ts:
--------------------------------------------------------------------------------
1 | export {};
2 |
--------------------------------------------------------------------------------
/src/test/runTest.ts:
--------------------------------------------------------------------------------
1 | import * as path from 'path';
2 |
3 | import { runTests } from '@vscode/test-electron';
4 |
5 | async function main() {
6 | try {
7 | // The folder containing the Extension Manifest package.json
8 | // Passed to `--extensionDevelopmentPath`
9 | const extensionDevelopmentPath = path.join(__dirname, '../../');
10 |
11 | // The path to test runner
12 | // Passed to --extensionTestsPath
13 | const extensionTestsPath = path.join(__dirname, './suite/index');
14 |
15 | // Download VS Code, unzip it and run the integration test
16 | await runTests({ extensionDevelopmentPath, extensionTestsPath });
17 | } catch (err) {
18 | console.error('Failed to run tests');
19 | process.exit(1);
20 | }
21 | }
22 |
23 | main();
24 |
--------------------------------------------------------------------------------
/src/test/suite/extension.test.d.ts:
--------------------------------------------------------------------------------
1 | export {};
2 |
--------------------------------------------------------------------------------
/src/test/suite/index.d.ts:
--------------------------------------------------------------------------------
1 | export declare function run(): Promise;
2 |
--------------------------------------------------------------------------------
/src/test/suite/index.ts:
--------------------------------------------------------------------------------
1 | import * as path from 'path';
2 | import { glob } from 'glob';
3 | import Mocha from 'mocha';
4 |
5 | export function run(): Promise {
6 | // Create the mocha test
7 | const mocha = new Mocha({
8 | ui: 'tdd',
9 | color: true
10 | });
11 |
12 | const testsRoot = path.join(__dirname, '..');
13 |
14 | return new Promise((c, e) => {
15 | glob('**/**.test.js', { cwd: testsRoot }, (err, files) => {
16 | if (err) {
17 | return e(err);
18 | }
19 |
20 | // Add files to the test suite
21 | files.forEach(f => mocha.addFile(path.join(testsRoot, f)));
22 |
23 | try {
24 | // Run the mocha test
25 | mocha.run(failures => {
26 | if (failures > 0) {
27 | e(new Error(`${failures} tests failed.`));
28 | } else {
29 | c();
30 | }
31 | });
32 | } catch (err) {
33 | console.error(err);
34 | e(err);
35 | }
36 | });
37 | });
38 | }
39 |
--------------------------------------------------------------------------------
/src/test/suite/input.test.ts:
--------------------------------------------------------------------------------
1 | import * as assert from 'assert';
2 |
3 |
4 | // You can import and use all API from the 'vscode' module
5 | // as well as import your extension to test it
6 | import * as vscode from 'vscode';
7 | import * as J from '../..';
8 | import { TestLogger } from '../TestLogger';
9 |
10 | suite.skip('Open Journal Entries', () => {
11 | vscode.window.showInformationMessage('Start all tests.');
12 |
13 | /* */
14 | test('Simple', async () => {
15 | assert.strictEqual(-1, [1, 2, 3].indexOf(5));
16 | assert.strictEqual(-1, [1, 2, 3].indexOf(0));
17 | })
18 | ;
19 | test("Input '+1'", async () => {
20 | let config: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("journal");
21 | let ctrl = new J.Util.Ctrl(config);
22 | ctrl.logger = new TestLogger(false);
23 |
24 |
25 | let parser = new J.Actions.Parser(ctrl);
26 | let input = await parser.parseInput("+1");
27 |
28 |
29 | assert.strictEqual(1, input.offset);
30 | })
31 | ;
32 |
33 | test("Input '2021-05-12'", async () => {
34 | let config: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("journal");
35 | let ctrl = new J.Util.Ctrl(config);
36 | ctrl.logger = new TestLogger(false);
37 |
38 |
39 | let parser = new J.Actions.Parser(ctrl);
40 | let input = await parser.parseInput("2021-05-12");
41 |
42 | assert.strictEqual(input.offset > 0 || input.offset <= 0, true);
43 | })
44 | ;
45 |
46 | test("Input '05-12'", async () => {
47 | let config: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("journal");
48 | let ctrl = new J.Util.Ctrl(config);
49 | ctrl.logger = new TestLogger(false);
50 |
51 |
52 | let parser = new J.Actions.Parser(ctrl);
53 | let input = await parser.parseInput("05-12");
54 |
55 | assert.strictEqual(input.offset > 0 || input.offset <= 0, true);
56 | })
57 | ;
58 |
59 | test("Input '12'", async () => {
60 | let config: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("journal");
61 | let ctrl = new J.Util.Ctrl(config);
62 | ctrl.logger = new TestLogger(false);
63 |
64 |
65 | let parser = new J.Actions.Parser(ctrl);
66 | let input = await parser.parseInput("12");
67 |
68 | assert.strictEqual(input.offset > 0 || input.offset <= 0, true);
69 | })
70 | ;
71 |
72 | test("Input 'next monday'", async () => {
73 | let config: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("journal");
74 | let ctrl = new J.Util.Ctrl(config);
75 | ctrl.logger = new TestLogger(false);
76 |
77 |
78 | let parser = new J.Actions.Parser(ctrl);
79 | let input = await parser.parseInput("next monday");
80 |
81 |
82 | assert.ok(input.offset > 0, "Offset not > 0, is "+input.offset);
83 | });
84 |
85 | test("Input 'next tue'", async () => {
86 | let config: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("journal");
87 | let ctrl = new J.Util.Ctrl(config);
88 | ctrl.logger = new TestLogger(false);
89 |
90 |
91 | let parser = new J.Actions.Parser(ctrl);
92 | let input = await parser.parseInput("next tue");
93 |
94 | assert.ok(input.offset > 0, "Offset not > 0, is "+input.offset);
95 | });
96 |
97 | test("Input 'last wed'", async () => {
98 | let config: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("journal");
99 | let ctrl = new J.Util.Ctrl(config);
100 | ctrl.logger = new TestLogger(false);
101 |
102 |
103 | let parser = new J.Actions.Parser(ctrl);
104 | let input = await parser.parseInput("last wed");
105 |
106 | assert.ok(input.offset < 0, "Offset not < 0, is "+input.offset);
107 | });
108 |
109 |
110 | test("Input 'task +1 do this'", async () => {
111 | let config: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("journal");
112 | let ctrl = new J.Util.Ctrl(config);
113 | ctrl.logger = new TestLogger(false);
114 |
115 |
116 | let parser = new J.Actions.Parser(ctrl);
117 | let input = await parser.parseInput("task +1 text");
118 |
119 | assert.ok(input.offset > 0, "Offset not > 0, is " + input.offset);
120 | assert.ok(input.hasFlags(), "Input has no flags " + JSON.stringify(input));
121 | assert.ok(input.hasTask(), "Input has no task flag " + JSON.stringify(input));
122 | assert.ok(input.text.length > 0, "Input has no text " + JSON.stringify(input));
123 | });
124 |
125 | test("Input 'task next wed do this'", async () => {
126 | let config: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("journal");
127 | let ctrl = new J.Util.Ctrl(config);
128 | ctrl.logger = new TestLogger(false);
129 |
130 |
131 | let parser = new J.Actions.Parser(ctrl);
132 | let input = await parser.parseInput("task next wed text");
133 |
134 | assert.ok(input.offset > 0, "Offset not > 0, is " + input.offset);
135 | assert.ok(input.hasFlags(), "Input has no flags " + JSON.stringify(input));
136 | assert.ok(input.hasTask(), "Input has no task flag " + JSON.stringify(input));
137 | assert.ok(input.text.length > 0, "Input has no text " + JSON.stringify(input));
138 | });
139 |
140 |
141 |
142 | });
143 |
--------------------------------------------------------------------------------
/src/test/suite/notes_sync.test.ts:
--------------------------------------------------------------------------------
1 | import * as assert from 'assert';
2 |
3 |
4 | // You can import and use all API from the 'vscode' module
5 | // as well as import your extension to test it
6 | import * as vscode from 'vscode';
7 | import * as J from '../..';
8 | import { LoadNotes } from '../../provider';
9 | import { ShowEntryForInputCommand, ShowEntryForTodayCommand } from '../../provider/commands';
10 | import { TestLogger } from '../TestLogger';
11 |
12 | suite.skip('Test Notes Syncing', () => {
13 |
14 | test('Sync notes', async () => {
15 |
16 |
17 | let config: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("journal");
18 | let ctrl = new J.Util.Ctrl(config);
19 | ctrl.logger = new TestLogger(false);
20 |
21 | // create a new entry.. remember length
22 | await vscode.commands.executeCommand("journal.today");
23 | let editor = vscode.window.activeTextEditor;
24 | assert.ok(editor, "Failed to open today's journal");
25 |
26 | let originalLength = editor.document.getText().length;
27 | assert.ok(originalLength > 0, "Nothing in document");
28 |
29 | // create a new note
30 | let input = new J.Model.NoteInput();
31 | input.text = "This is a test note";
32 | let notesDoc : vscode.TextDocument = await new LoadNotes(input, ctrl).load();
33 | let notesEditor = await ctrl.ui.showDocument(notesDoc);
34 | assert.ok(notesEditor, "Failed to open note");
35 |
36 | await new Promise( resolve => setTimeout(resolve, 2000));
37 |
38 | await vscode.commands.executeCommand("journal.today");
39 | let editorAgain = vscode.window.activeTextEditor;
40 | assert.ok(editorAgain, "Failed to open today's journal");
41 |
42 | let newLength = editorAgain.document.getText().length;
43 |
44 | assert.ok(newLength > originalLength, "Notes link wasn't injected");
45 |
46 | // check length of new entry
47 | }).timeout(5000)
48 | ;
49 | });
--------------------------------------------------------------------------------
/src/test/suite/read_templates.test.ts:
--------------------------------------------------------------------------------
1 | import * as assert from 'assert';
2 | import moment = require('moment');
3 |
4 | // You can import and use all API from the 'vscode' module
5 | // as well as import your extension to test it
6 | import * as vscode from 'vscode';
7 | import * as J from '../..';
8 | import { TestLogger } from '../TestLogger';
9 | import { suite, before, test } from 'mocha';
10 | import { Ctrl } from '../../util';
11 | import { fstat } from 'fs';
12 | import path = require('path');
13 |
14 | suite('Read templates from configuration', () => {
15 | let ctrl: J.Util.Ctrl;
16 |
17 | before(() => {
18 | let config: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("journal");
19 | ctrl = new J.Util.Ctrl(config);
20 | ctrl.logger = new TestLogger(true);
21 |
22 | });
23 |
24 |
25 |
26 | test.skip('Sync scopes', async () => {
27 | const scopes = ctrl.config.getScopes();
28 | assert.strictEqual(scopes.length, 3, "Invalid scope number");
29 | });
30 |
31 | test.skip('Test resolving note paths', async () => {
32 | const inPriv = new J.Model.Input(0);
33 | inPriv.text = "#priv a note created in private scope";
34 | const pathPriv = await ctrl.parser.resolveNotePathForInput(inPriv);
35 | const uriPriv = vscode.Uri.file(pathPriv);
36 |
37 |
38 | const inWork = new J.Model.Input(0);
39 | inWork.text = "#work a note created in work scope";
40 | const pathWork = await ctrl.parser.resolveNotePathForInput(inWork);
41 | const uriWork = vscode.Uri.file(pathWork);
42 |
43 |
44 | assert.ok(uriWork.path.match(/.*\/work\/.*/), "Wrong path to work note: "+uriWork.path);
45 | assert.ok(uriPriv.path.match(/\/private\//), "Wrong path to private note: "+uriPriv.path);
46 |
47 | });
48 | test('Create notes in different scopes', async () => {
49 | const scopes = ctrl.config.getScopes();
50 | assert.strictEqual(scopes.length, 3, "Invalid scope number");
51 |
52 |
53 | let a = ctrl.config.getScopes();
54 |
55 | // create a new note
56 | const privInput = await ctrl.parser.parseInput("#priv a note created in private scop");
57 | let privNotes = await new J.Provider.LoadNotes(privInput, ctrl);
58 | let privDoc: vscode.TextDocument = await privNotes.load();
59 | privDoc = await ctrl.ui.saveDocument(privDoc);
60 | const privUri = privDoc.uri;
61 |
62 |
63 |
64 | const workInput = await ctrl.parser.parseInput("#work a note created in work scope");
65 | let workDoc: vscode.TextDocument = await new J.Provider.LoadNotes(workInput, ctrl).load();
66 | workDoc = await ctrl.ui.saveDocument(workDoc);
67 | const uriWork = workDoc.uri;
68 |
69 |
70 | assert.ok(uriWork.path.match(/.*\/work\/.*/), "Wrong path to work note: "+uriWork.path);
71 | assert.ok(privUri.path.match(/\/private\//), "Wrong path to private note: "+privUri.path);
72 | }).timeout(50000);
73 |
74 | });
--------------------------------------------------------------------------------
/src/test/suite/week_input.test.ts:
--------------------------------------------------------------------------------
1 | import * as assert from 'assert';
2 | import moment = require('moment');
3 |
4 | // You can import and use all API from the 'vscode' module
5 | // as well as import your extension to test it
6 | import * as vscode from 'vscode';
7 | import * as J from '../..';
8 | import { TestLogger } from '../TestLogger';
9 | import {suite, before,test} from 'mocha';
10 |
11 |
12 | suite.skip('Open Week Entries', () => {
13 | vscode.window.showInformationMessage('Start all tests.');
14 | let ctrl: J.Util.Ctrl;
15 |
16 | before(() => {
17 | let config: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("journal");
18 | ctrl = new J.Util.Ctrl(config);
19 | ctrl.logger = new TestLogger(false);
20 |
21 | });
22 |
23 | test("Input 'w13'", async () => {
24 |
25 | let parser = new J.Actions.Parser(ctrl);
26 | let input = await parser.parseInput("w13");
27 |
28 | assert.ok(! input.hasOffset(), "Offset is set, is " + input.offset);
29 | assert.ok(! input.hasFlags(), "Input has flags " + JSON.stringify(input));
30 | assert.ok(! input.hasTask(), "Input has task flag " + JSON.stringify(input));
31 | assert.ok(! input.hasText(), "Input has no text " + JSON.stringify(input));
32 | assert.ok(input.hasWeek(), "Input has no week definition " + JSON.stringify(input));
33 | });
34 |
35 |
36 | test("Input 'w'", async () => {
37 | let config: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("journal");
38 | let ctrl = new J.Util.Ctrl(config);
39 | ctrl.logger = new TestLogger(false);
40 |
41 | let parser = new J.Actions.Parser(ctrl);
42 | let input = await parser.parseInput("w");
43 | let currentWeek = moment().week();
44 |
45 | assert.ok(!input.hasOffset(), "Offset is set, is " + input.offset);
46 | assert.ok(!input.hasFlags(), "Input has flags " + JSON.stringify(input));
47 | assert.ok(!input.hasTask(), "Input has task flag " + JSON.stringify(input));
48 | assert.ok(!input.hasText(), "Input has no text " + JSON.stringify(input));
49 | assert.ok(input.hasWeek(), "Input has no week definition " + JSON.stringify(input));
50 |
51 | assert.strictEqual(input.week, currentWeek, "weeks mismatch");
52 | });
53 |
54 | test("Input 'next week'", async () => {
55 | let config: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("journal");
56 | let ctrl = new J.Util.Ctrl(config);
57 | ctrl.logger = new TestLogger(false);
58 |
59 | let parser = new J.Actions.Parser(ctrl);
60 | let input = await parser.parseInput("next week");
61 |
62 | let currentWeek = moment().week();
63 |
64 | assert.ok(!input.hasOffset(), "Offset is set, is " + input.offset);
65 | assert.ok(!input.hasFlags(), "Input has flags " + JSON.stringify(input));
66 | assert.ok(!input.hasTask(), "Input has task flag " + JSON.stringify(input));
67 | assert.ok(!input.hasText(), "Input has no text " + JSON.stringify(input));
68 | assert.ok(input.hasWeek(), "Input has no week definition " + JSON.stringify(input));
69 |
70 | assert.strictEqual(input.week, currentWeek + 1, "weeks mismatch");
71 | });
72 |
73 | });
74 |
--------------------------------------------------------------------------------
/src/util/controller.ts:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2018 Patrick Maué
2 | //
3 | // This file is part of vscode-journal.
4 | //
5 | // vscode-journal is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // vscode-journal is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with vscode-journal. If not, see .
17 | //
18 |
19 |
20 | 'use strict';
21 |
22 |
23 | import * as J from '../.';
24 | import * as vscode from 'vscode';
25 |
26 | export class Ctrl {
27 |
28 |
29 | private _config: J.Extension.Configuration;
30 | private _ui: J.Extension.Dialogues;
31 | private _parser: J.Actions.Parser;
32 | private _writer: J.Actions.Writer;
33 | private _reader: J.Actions.Reader;
34 |
35 |
36 | private _logger: J.Util.Logger | undefined;
37 |
38 |
39 | private _inject: J.Actions.Inject;
40 |
41 |
42 | constructor(vscodeConfig: vscode.WorkspaceConfiguration) {
43 | this._config = new J.Extension.Configuration(vscodeConfig);
44 | this._parser = new J.Actions.Parser(this);
45 | this._writer = new J.Actions.Writer(this);
46 | this._reader = new J.Actions.Reader(this);
47 | this._inject = new J.Actions.Inject(this);
48 | this._ui = new J.Extension.Dialogues(this);
49 | }
50 |
51 |
52 |
53 | /**
54 | * Getter $ui
55 | * @return {J.Extension.VSCode}
56 | */
57 | public get ui(): J.Extension.Dialogues {
58 | return this._ui;
59 | }
60 |
61 | /**
62 | * Getter $writer
63 | * @return {J.Actions.Writer}
64 | */
65 | public get writer(): J.Actions.Writer {
66 | return this._writer;
67 | }
68 |
69 | /**
70 | * Getter $reader
71 | * @return {J.Actions.Reader}
72 | */
73 | public get reader(): J.Actions.Reader {
74 | return this._reader;
75 | }
76 |
77 | /**
78 | * Getter $parser
79 | * @return {J.Actions.Parser}
80 | */
81 | public get parser(): J.Actions.Parser {
82 | return this._parser;
83 | }
84 |
85 | /**
86 | * Getter $config
87 | * @return {J.Extension.Configuration}
88 | */
89 | public get config(): J.Extension.Configuration {
90 | return this._config;
91 | }
92 |
93 | /**
94 | * Getter inject
95 | * @return {J.Actions.Inject}
96 | */
97 | public get inject(): J.Actions.Inject {
98 | return this._inject;
99 | }
100 |
101 | /**
102 | * Getter logger
103 | * @return {J.Util.Logger}
104 | */
105 | public get logger(): J.Util.Logger {
106 | if(J.Util.isNullOrUndefined(this._logger)) { throw Error("Tried to access undefined logger in journal"); }
107 | return this._logger!;
108 | }
109 |
110 | /**
111 | * Setter logger
112 | * @param {J.Util.Logger} value
113 | */
114 | public set logger(value: J.Util.Logger) {
115 | this._logger = value;
116 | }
117 |
118 |
119 | }
--------------------------------------------------------------------------------
/src/util/index.d.ts:
--------------------------------------------------------------------------------
1 | export { Ctrl } from './controller';
2 | export { ConsoleLogger, Logger } from './logger';
3 | export { checkIfFileIsAccessible, denormalizeFilename, formatDate, getDayAsString, getDayOfWeekForString, getEntryPathForDate, getFileInURI, getFilePathInDateFolder, getNextLine, getPathOfMonth, normalizeFilename, prefixZero, getPathAsString, isNotNullOrUndefined, isNullOrUndefined, stringIsNotEmpty, isError, isString } from './util';
4 |
--------------------------------------------------------------------------------
/src/util/index.ts:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2018 Patrick Maué
2 | //
3 | // This file is part of vscode-journal.
4 | //
5 | // vscode-journal is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // vscode-journal is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with vscode-journal. If not, see .
17 | //
18 |
19 |
20 | export { Ctrl } from './controller';
21 |
22 | export { ConsoleLogger, Logger } from './logger';
23 |
24 | export {
25 | isNotNullOrUndefined,
26 | isNullOrUndefined,
27 | isError
28 |
29 |
30 | } from './util';
31 |
32 |
33 | export {
34 | formatDate,
35 | getDayOfWeekForString,
36 | replaceDateFormats,
37 | replaceDateTemplatesWithMomentsFormats,
38 | getMonthForString
39 | }
40 | from './dates';
41 |
42 | export {
43 | getNextLine,
44 | denormalizeFilename,
45 | getDayAsString,
46 | isString,
47 | normalizeFilename,
48 | prefixZero,replaceVariableValue,stringIsNotEmpty
49 | }
50 | from './strings';
51 |
52 | export {
53 | checkIfFileIsAccessible,
54 | getDateFromURI,
55 | getDateFromURIAndConfig,
56 | getFileInURI,
57 | getFilePathInDateFolder,
58 | getPathAsString,
59 | getPathOfMonth,
60 | inferType,
61 | resolvePath
62 | }
63 | from './paths';
64 |
65 | /*
66 | declare module Comm {
67 | export const Comfiguration = _Configuration;
68 | export const TemplateInfo = _TemplateInfo;
69 | export const Util = _Util;
70 | }
71 |
72 | export namespace Common {
73 | export const Comfiguration = _Configuration;
74 | export const TemplateInfo = _TemplateInfo;
75 | export const Util = _Util;
76 | }
77 | */
--------------------------------------------------------------------------------
/src/util/logger.d.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import * as J from '../.';
3 | export interface Logger {
4 | trace(message: string, ...optionalParams: any[]): void;
5 | debug(message: string, ...optionalParams: any[]): void;
6 | error(message: string, ...optionalParams: any[]): void;
7 | printError(error: Error): void;
8 | showChannel(): void;
9 | }
10 | export declare class ConsoleLogger implements Logger {
11 | ctrl: J.Util.Ctrl;
12 | channel: vscode.OutputChannel;
13 | private devMode;
14 | constructor(ctrl: J.Util.Ctrl, channel: vscode.OutputChannel);
15 | showChannel(): void;
16 | traceLine(message: string, ...optionalParams: any[]): void;
17 | trace(message: string, ...optionalParams: any[]): void;
18 | debug(message: string, ...optionalParams: any[]): void;
19 | printError(error: Error): void;
20 | error(message: string, ...optionalParams: any[]): void;
21 | private appendCurrentTime;
22 | }
23 |
--------------------------------------------------------------------------------
/src/util/logger.ts:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2018 Patrick Maué
2 | //
3 | // This file is part of vscode-journal.
4 | //
5 | // vscode-journal is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // vscode-journal is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with vscode-journal. If not, see .
17 | //
18 |
19 |
20 | import moment = require('moment');
21 | import * as vscode from 'vscode';
22 | import * as J from '../.';
23 |
24 | export interface Logger {
25 | trace(message: string, ...optionalParams: any[]): void;
26 | debug(message: string, ...optionalParams: any[]): void;
27 | error(message: string, ...optionalParams: any[]): void;
28 | printError(error: Error): void;
29 | showChannel(): void;
30 | }
31 |
32 |
33 |
34 | export class ConsoleLogger implements Logger {
35 | private devMode = false;
36 |
37 |
38 | constructor(public ctrl: J.Util.Ctrl, public channel: vscode.OutputChannel) {
39 | this.devMode = ctrl.config.isDevelopmentModeEnabled();
40 | }
41 |
42 | public showChannel(): void {
43 | this.channel.show();
44 | }
45 |
46 | public traceLine(message: string, ...optionalParams: any[]): void {
47 | if (this.devMode === true) {
48 | this.appendCurrentTime();
49 | this.channel.append(" [trace] ");
50 |
51 | this.channel.append(message);
52 | optionalParams.forEach(msg => this.channel.append(msg+""));
53 |
54 | this.channel.appendLine("");
55 |
56 |
57 | console.trace("[TRACE]", message, ...optionalParams);
58 | }
59 | }
60 |
61 | public trace(message: string, ...optionalParams: any[]): void {
62 | if (this.devMode === true) {
63 | this.appendCurrentTime();
64 | this.channel.append(" [trace] ");
65 |
66 | this.channel.append(message);
67 | optionalParams.forEach(msg => this.channel.append(msg+""));
68 |
69 | this.channel.appendLine("");
70 |
71 | console.info("[TRACE]", message, ...optionalParams);
72 | }
73 | }
74 |
75 |
76 | public debug(message: string, ...optionalParams: any[]): void {
77 | if (this.devMode === true) {
78 | this.appendCurrentTime();
79 | this.channel.append(" [debug] ");
80 |
81 | this.channel.append(message);
82 | optionalParams.forEach(msg => this.channel.append(msg+""));
83 |
84 | this.channel.appendLine("");
85 |
86 | console.log("[DEBUG]", message, ...optionalParams);
87 | }
88 | }
89 |
90 | public printError(error: Error): void {
91 | this.error(error.message, error);
92 |
93 |
94 | }
95 |
96 | public error(message: string, ...optionalParams: any[]): void {
97 |
98 | this.appendCurrentTime();
99 | this.channel.append(" [ERROR] ");
100 |
101 | this.channel.append(message);
102 |
103 | if(optionalParams.length > 0) {
104 | this.channel.append(" ");
105 | }
106 | optionalParams.forEach(msg => {
107 | if(J.Util.isString(msg)) {
108 | this.channel.append(msg+"");
109 | }
110 | else if(J.Util.isError(msg)) {
111 | if(J.Util.isNotNullOrUndefined(msg.stack)) {
112 | let method: string | undefined = /at \w+\.(\w+)/.exec(msg.stack!.split('\n')[2])?.pop();
113 | this.channel.append("("+method+")");
114 | }
115 |
116 | this.channel.appendLine("See Exception below.");
117 | if(J.Util.isNotNullOrUndefined(msg.stack)) {
118 | this.channel.append(msg.stack);
119 | }
120 |
121 | }
122 | else {
123 | this.channel.appendLine(JSON.stringify(msg));
124 | }
125 | });
126 | this.channel.appendLine("");
127 |
128 | console.error("[ERROR]", message, ...optionalParams);
129 | }
130 |
131 |
132 |
133 | private appendCurrentTime() : void {
134 | this.channel.append("[");
135 | this.channel.append(moment(new Date()).format('HH:mm:ss.SSS'));
136 | this.channel.append("]");
137 | }
138 | }
139 |
140 |
--------------------------------------------------------------------------------
/src/util/startup.d.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import * as J from '../.';
3 | export declare class Startup {
4 | context: vscode.ExtensionContext;
5 | config: vscode.WorkspaceConfiguration;
6 | /**
7 | *
8 | */
9 | constructor(context: vscode.ExtensionContext, config: vscode.WorkspaceConfiguration);
10 | initialize(): Promise;
11 | registerLoggingChannel(ctrl: J.Util.Ctrl, context: vscode.ExtensionContext): Promise;
12 | registerCodeLens(ctrl: J.Util.Ctrl, context: vscode.ExtensionContext): Promise;
13 | registerCommands(ctrl: J.Util.Ctrl, context: vscode.ExtensionContext): Promise;
14 | /**
15 | * Sets default syntax highlighting settings on startup, we try to differentiate between dark and light themes
16 | *
17 | * @param {J.Util.Ctrl} ctrl
18 | * @param {vscode.ExtensionContext} context
19 | * @returns {Q.Promise}
20 | * @memberof Startup
21 | */
22 | registerSyntaxHighlighting(ctrl: J.Util.Ctrl): Promise;
23 | }
24 |
--------------------------------------------------------------------------------
/src/util/strings.ts:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2021 Patrick Maué
2 | //
3 | // This file is part of vscode-journal.
4 | //
5 | // vscode-journal is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // vscode-journal is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with vscode-journal. If not, see .
17 | //
18 |
19 | 'use strict';
20 |
21 | import { isNotNullOrUndefined } from '.';
22 |
23 |
24 | export function getDayAsString(date: Date): string {
25 | return prefixZero(date.getDate());
26 | }
27 |
28 | /**
29 | * Takes a number and a leading 0 if it is only one digit, e.g. 9 -> "09"
30 | */
31 | export function prefixZero(nr: number): string {
32 | let current = nr.toString();
33 | if (current.length === 1) { current = '0' + current; }
34 | return current;
35 | }
36 |
37 | /**
38 | * Returns a normalized filename for given string. Special characters will be replaced.
39 | * @param input
40 | */
41 | export function normalizeFilename(input: string): string {
42 | let result = input.trim();
43 | result = result.replace(/\s/g, '_');
44 | result = result.replace(/\\|\/|\<|\>|\:|\n|\||\?|\*/g, '-');
45 | return result;
46 | }
47 |
48 | /**
49 | * Converts a filename into its readable form (for file links)
50 | *
51 | * @param input the line to convert
52 | * @param ext the file extension used for notes and journal entries
53 | */
54 | export function denormalizeFilename(input: string): string {
55 |
56 | input = input.substring(0, input.lastIndexOf("."));
57 | input = input.replace(/_/g, " ");
58 | input = input.replace(/-/g, " ");
59 |
60 | return input;
61 | }
62 |
63 | export function stringIsNotEmpty(value: string | undefined | null) : boolean {
64 | return value !== null && value !== undefined && value.length > 0;
65 | }
66 |
67 | export function isString(object: any | string | undefined ): boolean {
68 | return isNotNullOrUndefined(object) && typeof object === 'string';
69 | }
70 |
71 |
72 |
73 | export function replaceVariableValue(key: string, value: string, template: string): string {
74 | if (template.search("\\$\\{" + key + "\\}") >= 0) {
75 | return template.replace("${" + key + "}", value);
76 | } else {
77 | return template;
78 | }
79 | }
80 |
81 |
82 | export function getNextLine(content: string): string[] {
83 |
84 | let res: string[] = ["", ""];
85 |
86 | let pos: number = content.indexOf('\n');
87 | if (pos > 0) {
88 | res[0] = content.slice(0, pos);
89 | res[1] = content.slice(pos + 1, content.length);
90 | } else {
91 | res[0] = content;
92 | }
93 | return res;
94 | }
--------------------------------------------------------------------------------
/src/util/util.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | import * as Path from 'path';
3 | /**
4 | * Utility Methods for the vscode-journal extension
5 | */
6 | /**
7 | * Check if config dir exists, otherwise copy defaults from extension directory
8 | * We can't Q's nfcall, since those nodejs operations don't have (err,data) responses
9 | *
10 | * fs.exists does only return "true", see https://github.com/petkaantonov/bluebird/issues/418
11 | * @param path
12 | */
13 | export declare function checkIfFileIsAccessible(path: string): Promise;
14 | /**
15 | * Return day of week for given string.
16 | */
17 | export declare function getDayOfWeekForString(day: string): number;
18 | /**
19 | * Formats a given Date in long format (for Header in journal pages)
20 | */
21 | export declare function formatDate(date: Date, template: string, locale: string): string;
22 | /**
23 | * Returns target for notes as string;
24 | */
25 | export declare function getFilePathInDateFolder(date: Date, filename: string, base: string, ext: string): Promise;
26 | /**
27 | * Returns the path for a given date as string
28 | * @deprecated
29 | */
30 | export declare function getEntryPathForDate(date: Date, base: string, ext: string): Promise;
31 | export declare function getPathAsString(path: Path.ParsedPath): string;
32 | /**
33 | * Returns the filename of a given URI.
34 | * Example: "21" of uri "file://some/path/to/21.md""
35 | * @param uri
36 | */
37 | export declare function getFileInURI(uri: string, withExtension?: boolean): string;
38 | export declare function getNextLine(content: string): string[];
39 | /**
40 | * Returns path to month folder.
41 | */
42 | export declare function getPathOfMonth(date: Date, base: string): string;
43 | export declare function getDayAsString(date: Date): string;
44 | /**
45 | * Takes a number and a leading 0 if it is only one digit, e.g. 9 -> "09"
46 | */
47 | export declare function prefixZero(nr: number): string;
48 | /**
49 | * Returns a normalized filename for given string. Special characters will be replaced.
50 | * @param input
51 | */
52 | export declare function normalizeFilename(input: string): string;
53 | /**
54 | * Converts a filename into its readable form (for file links)
55 | *
56 | * @param input the line to convert
57 | * @param ext the file extension used for notes and journal entries
58 | */
59 | export declare function denormalizeFilename(input: string): string;
60 | export declare function isNullOrUndefined(value: any | undefined | null): boolean;
61 | export declare function isNotNullOrUndefined(value: any | undefined | null): boolean;
62 | export declare function stringIsNotEmpty(value: string | undefined | null): boolean;
63 | export declare function isString(object: any | string | undefined): boolean;
64 | export declare function isError(object: any | Error | undefined): boolean;
65 |
--------------------------------------------------------------------------------
/src/util/util.ts:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2018 Patrick Maué
2 | //
3 | // This file is part of vscode-journal.
4 | //
5 | // vscode-journal is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // vscode-journal is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with vscode-journal. If not, see .
17 | //
18 |
19 |
20 |
21 | 'use strict';
22 | import { types } from 'util';
23 |
24 | export function isNullOrUndefined(value: any | undefined | null): boolean {
25 | return value === null || value === undefined;
26 | }
27 |
28 |
29 | export function isNotNullOrUndefined(value: any | undefined | null): boolean {
30 | return value !== null && value !== undefined;
31 | }
32 |
33 |
34 | export function isError(object: any | Error | undefined ): boolean {
35 | return isNotNullOrUndefined(object) && types.isNativeError(object);
36 | }
37 |
38 |
--------------------------------------------------------------------------------
/test/Readme.md:
--------------------------------------------------------------------------------
1 | # Test workspaces
2 |
3 | * ws_manual -> default workspace for extension tests
4 | * ws_unittests -> workspace for the unit tests (has to be cleaned before each test)
5 |
6 | Both are configured in launch.json
--------------------------------------------------------------------------------
/test/backup/user-settings.cjson:
--------------------------------------------------------------------------------
1 | {
2 | "opa.path": "C:\\Users\\patrick.maue\\opa.exe",
3 | "git.ignoreMissingGitWarning": true,
4 | "workbench.colorTheme": "Visual Studio Dark",
5 |
6 | "git.autofetch": true,
7 | "terminal.integrated.defaultProfile.windows": "Git Bash",
8 | "vscode-kubernetes.helm-path": "C:\\Users\\patrick.maue\\AppData\\Local\\Microsoft\\WindowsApps\\oc.exe",
9 | "vs-kubernetes": {
10 | "vscode-kubernetes.kubectl-path.windows": "C:\\Users\\patrick.maue\\.vs-kubernetes\\tools\\kubectl\\kubectl.exe",
11 | "vscode-kubernetes.minikube-path.windows": "C:\\Users\\patrick.maue\\.vs-kubernetes\\tools\\minikube\\windows-amd64\\minikube.exe"
12 | },
13 | "redhat.telemetry.enabled": false,
14 | "editor.tokenColorCustomizations": {
15 | "textMateRules": [
16 | {
17 | "scope": "text.html.markdown.journal.task.open.bullet",
18 | "settings": {
19 | "foreground": "#FFFF00"
20 | }
21 | },
22 | {
23 | "scope": "text.html.markdown.journal.task.open.marker",
24 | "settings": {
25 | "foreground": "#FFFF00"
26 | }
27 | },
28 | {
29 | "scope": "text.html.markdown.journal.task.open.keyword",
30 | "settings": {
31 | "fontStyle": "italic"
32 | }
33 | },
34 | {
35 | "scope": "text.html.markdown.journal.task.open.text",
36 | "settings": {}
37 | },
38 | {
39 | "scope": "text.html.markdown.journal.task.completed.keyword",
40 | "settings": {
41 | "fontStyle": "italic"
42 | }
43 | },
44 | {
45 | "scope": "text.html.markdown.journal.task.completed.marker",
46 | "settings": {
47 | "foreground": "#AAAAAA"
48 | }
49 | },
50 | {
51 | "scope": "text.html.markdown.journal.task.completed.text",
52 | "settings": {
53 | "foreground": "#AAAAAA"
54 | }
55 | },
56 | {
57 | "scope": "text.html.markdown.journal.task.completed.bullet",
58 | "settings": {
59 | "foreground": "#FFFF00"
60 | }
61 | },
62 | {
63 | "scope": "text.html.markdown.journal.memo.keyword",
64 | "settings": {
65 | "fontStyle": "italic"
66 | }
67 | },
68 | {
69 | "scope": "text.html.markdown.journal.memo.bullet",
70 | "settings": {
71 | "foreground": "#FFFF00"
72 | }
73 | },
74 | {
75 | "scope": "text.html.markdown.journal.scope",
76 | "settings": {
77 | "foreground": "#FFFF00"
78 | }
79 | },
80 | {
81 | "scope": "text.html.markdown.journal.link.keyword",
82 | "settings": {
83 | "fontStyle": "italic"
84 | }
85 | },
86 | {
87 | "scope": "text.html.markdown.journal.link.bullet",
88 | "settings": {
89 | "foreground": "#FFFF00"
90 | }
91 | }
92 | ]
93 | },
94 | "journal.locale": "de-DE",
95 | "journal.scopes": [
96 |
97 |
98 |
99 |
100 | {
101 | "name": "work",
102 | "patterns": {
103 | "notes": {
104 | "path": "${base}/scopes/work",
105 | "file": "${month}-${day}-${input}.${ext}"
106 | },
107 | }
108 | },
109 |
110 | {
111 | "name": "plan",
112 | "patterns": {
113 | "notes": {
114 | "path": "${base}/scopes/plan",
115 | "file": "${year}-${input}.${ext}"
116 | },
117 | }
118 | },
119 | {
120 | "name": "priv",
121 | "patterns": {
122 | "notes": {
123 | "path": "${base}/scopes/private",
124 | "file": "${month}-${input}.${ext}"
125 | },
126 | }
127 | },
128 | {
129 | "name": "diga",
130 | "patterns": {
131 | "notes": {
132 | "path": "${base}/scopes/diga",
133 | "file": "${localDate}-${input}.${ext}"
134 | },
135 | }
136 | }
137 | ],
138 | "journal.templates": [
139 |
140 | {
141 | "name": "memo",
142 | "template": "- Memo: ${input} (created: ${localTime}) "
143 | },
144 | {
145 | "name": "task",
146 | "template": "- [] Task: ${input} (created: ${localTime})",
147 | "after": "## Tasks"
148 | },
149 | {
150 | "name": "event",
151 | "template": "- [!] Task: ${input} (created: ${localTime})"
152 | },
153 | {
154 | "name": "entry",
155 | "template": "# ${d:dddd, MMMM DD YYYY}\n\n## Tasks\n\n## Notes\n\n"
156 | },
157 | {
158 | "name": "time",
159 | "template": "${localTime}"
160 | },
161 | {
162 | "name": "note",
163 | "template": "# ${input}\n\n${tags}\n"
164 | },
165 | {
166 | "name": "files",
167 | "template": "- NOTE: [${title}](${link})",
168 | "after": "## Notes"
169 |
170 | }
171 | ],
172 | "journal.patterns": {
173 |
174 |
175 |
176 |
177 | "notes": {
178 | "path": "${base}/${year}/${month}/${day}",
179 | "file": "${input}.${ext}"
180 | },
181 | "entries": {
182 | "path": "${base}/${year}/${month}",
183 | "file": "${day}.${ext}"
184 | },
185 | "weeks": {
186 | "path": "${base}/${year}",
187 | "file": "week_${week}.${ext}"
188 | }
189 | },
190 | "diffEditor.ignoreTrimWhitespace": false,
191 | "journal.dev": false,
192 | "journal.base": "C:\\Users\\pajom\\OneDrive\\Journal",
193 | "settingsSync.ignoredSettings": [
194 | "journal.base"
195 | ],
196 | "[markdown]": {
197 | // quickSuggestions true will provide suggestions as you type.
198 | // If you turn this on and DO NOT want suggestions
199 | // for non-wiki-link, non-tag words,
200 | "editor.quickSuggestions": true,
201 | // This is poorly documented, but seems to offer suggestions
202 | // from any word in open document when turned on, which
203 | // can be a little distracting in markdown docs:
204 | "editor.wordBasedSuggestions": false,
205 | "editor.tabSize": 2,
206 | // Set this to false if you turn on quickSuggestions
207 | // but don't want suggestions for markdown related snippets
208 | // as you type:
209 | "editor.suggest.showSnippets": true,
210 | },
211 | "editor.quickSuggestions": {
212 |
213 | "other": "on",
214 | "comments": "off",
215 | "strings": "off",
216 |
217 | },
218 | "security.workspace.trust.untrustedFiles": "open"
219 |
220 | }
--------------------------------------------------------------------------------
/test/ws_manual/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.vscode
3 | !.gitignore
--------------------------------------------------------------------------------
/test/ws_unittests/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.vscode
3 | !.gitignore
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "skipLibCheck": true, /* otherwise lint is printing a lot of errors */
4 | "module": "Node16",
5 | "target": "ES2022",
6 | "lib": [
7 | "ES2022"
8 | ],
9 | "outDir": "out",
10 | "rootDirs": ["src"],
11 | "resolveJsonModule": true, /* required to import translations.json */
12 | /* Strict Type-Checking Option */
13 | "strict": true, /* enable all strict type-checking options */
14 | /* Additional Checks */
15 | // "noUnusedLocals": false /* Report errors on unused locals. */
16 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
17 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
18 | // "noUnusedParameters": true, /* Report errors on unused parameters. */
19 | // "esModuleInterop": true,
20 | // "allowSyntheticDefaultImports": true,
21 | // "experimentalDecorators": true,
22 | // "emitDecoratorMetadata": true,
23 | "sourceMap": true,
24 | "declaration": true,
25 | }
26 | }
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | //@ts-check
2 |
3 | 'use strict';
4 |
5 | const path = require('path');
6 |
7 | //@ts-check
8 | /** @typedef {import('webpack').Configuration} WebpackConfig **/
9 |
10 | /** @type WebpackConfig */
11 | const extensionConfig = {
12 | target: 'node', // vscode extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/
13 | mode: 'none', // this leaves the source code as close as possible to the original (when packaging we set this to 'production')
14 |
15 | entry: './src/extension.ts', // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/
16 | output: {
17 | // the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/
18 | path: path.resolve(__dirname, 'dist'),
19 | filename: 'extension.js',
20 | libraryTarget: 'commonjs2'
21 | },
22 | externals: {
23 | vscode: 'commonjs vscode' // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/
24 | // modules added here also need to be added in the .vscodeignore file
25 | },
26 | resolve: {
27 | // support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader
28 | extensions: ['.ts', '.js']
29 | },
30 | module: {
31 | rules: [
32 | {
33 | test: /\.ts$/,
34 | exclude: /node_modules/,
35 | use: [
36 | {
37 | loader: 'ts-loader'
38 | }
39 | ]
40 | }
41 | ]
42 | },
43 | devtool: 'nosources-source-map',
44 | infrastructureLogging: {
45 | level: "log", // enables logging required for problem matchers
46 | },
47 | };
48 | module.exports = [ extensionConfig ];
--------------------------------------------------------------------------------