Repository: vnotex/vnote
Stars: 12771
CLAUDE.md
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
VNote is a Qt-based, cross-platform (Windows/Linux/macOS) note-taking application focused on Markdown. It uses C++14, Qt 6, and CMake 3.20+. The project is undergoing a major architectural migration from singletons to dependency injection via ServiceLocator.
Build Commands
Setup (first time after clone)
bash scripts/init.sh # Linux/macOS
scripts\init.cmd # WindowsConfigure + build (Release)
mkdir build && cd build
cmake .. -GNinja # Windows with MSVC: run from VS Developer Command Prompt
cmake --build . --config ReleaseDebug build
cmake .. -DCMAKE_BUILD_TYPE=Debug
cmake --build . --config DebugClean rebuild
rm -rf build && mkdir build && cd build && cmake .. && cmake --build .Testing
Tests use Qt Test framework. Always call vxcore_set_test_mode(1) before vxcore_context_create() in tests to prevent corrupting real user data.
Build all tests
cmake --build build --config ReleaseRun all tests via CTest
ctest --test-dir build --output-on-failureRun a single test (pattern match)
ctest --test-dir build -R test_errorRun test executable directly (Windows: Qt DLLs must be in PATH)
./build/tests/core/test_error.exeAdding a New Test
Use the add_qt_test() helper in tests/<module>/CMakeLists.txt:
add_qt_test(test_myclass
SOURCES test_myclass.cpp ${CMAKE_SOURCE_DIR}/src/module/myclass.cpp
LINKS core_services vxcore # Optional extra link libraries
GUILESS # Optional: headless (QCoreApplication)
)Test files use QTEST_GUILESS_MAIN(tests::TestClassName) and must end with #include "test_filename.moc".
Architecture
Dual Architecture (Legacy + New)
The codebase has two coexisting architectures:
- Legacy: Singleton-based (VNoteX::getInst(), ConfigMgr::getInst()) â do NOT use for new code
- New (files with 2 suffix): Dependency injection via ServiceLocator passed through constructors
New files coexist with legacy via the 2 suffix convention (e.g., MainWindow2, ConfigMgr2, Buffer2).
MVC + Service Layer
Controllers (src/controllers/) â business logic, QObject (not QWidget), testable
â signals/slots
Models (src/models/) â QAbstractItemModel subclasses, no UI logic
Views (src/views/) â QTreeView/delegates, display only, emit signals
â
ServiceLocator â DI container (non-owning pointers, NOT a singleton)
â
Services (src/core/services/) â wrap vxcore C API with Qt-friendly interface
â
vxcore (libs/vxcore/) â C library: notebook/config/search backendMVC rules: Models must not contain UI logic. Views must not modify data directly. Controllers must not inherit QWidget. All layers receive ServiceLocator& via constructor.
Key Types
| Type | Role |
|------|------|
| ServiceLocator | DI container; stores non-owning void* pointers keyed by type_index |
| NodeIdentifier | Lightweight value type: notebookId (GUID) + relativePath |
| Buffer2 | Lightweight copyable handle (like QModelIndex), returned by BufferService::openBuffer() |
| XXXCoreService | Low-level services wrapping vxcore C API (hold VxCoreContextHandle) |
| BufferService | Hook-aware wrapper over BufferCoreService; fires vnote.file.* hooks |
| HookManager | WordPress-style hook system: actions (cancellable events) + filters (data transforms) |
Service Registration (main.cpp)
Services are stack-allocated in main() within a scoped block, registered as non-owning pointers in ServiceLocator, and destroyed before vxcore_context_destroy(). Order matters.
Hook System
Plugins use HookManager::addAction() / addFilter() with priority ordering. Hook names are constants in src/core/hooknames.h (e.g., vnote.notebook.before_open, vnote.file.before_save). Actions can cancel operations via HookContext::cancel(). When adding hooks to existing code, use the WRAP pattern: fire before-hook â original signal â after-hook.
Git Submodules
Three submodules in libs/:
- vtextedit â Rich text/Markdown editor widget
- QHotkey â Cross-platform global hotkey support
- vxcore â C library backend (built as static lib, tests/CLI disabled)
Code Style
Enforced by .clang-format via pre-commit hook. Key conventions:
- C++14, 2-space indent, 100-char line limit
- Naming: CamelCase classes, camelCase methods, p_ params, m_ members, c_ constants
- Pointer alignment: right (int *ptr)
- Include order: own header â Qt â local/project â using namespace vnotex; in .cpp only
- Header guards: #ifndef CLASSNAME_H / #define CLASSNAME_H
- Namespace: single vnotex namespace; never using namespace in headers
- libs/ directory is excluded from formatting (third-party code)
Manual formatting
clang-format -i src/core/myfile.cppDirectory Layout (New Architecture)
| Directory | Contents |
|-----------|----------|
| src/core/services/ | Service layer (core_services static library, links vxcore) |
| src/core/ | Core types, legacy code, config, hook system |
| src/controllers/ | MVC controllers |
| src/models/ | MVC models |
| src/views/ | MVC views and delegates |
| src/widgets/ | UI widgets (receive ServiceLocator&), including dialogs/ |
| src/gui/services/ | GUI-aware services (ThemeService, ViewWindowFactory) |
| src/gui/utils/ | GUI utility helpers |
| tests/ | Qt Test suites; helpers/ has TempDirFixture and common includes |
| libs/ | Git submodules (vtextedit, QHotkey, vxcore) |
Migration Patterns
When migrating legacy code to new architecture:
1. Create new file with 2 suffix
2. Replace ConfigMgr::getInst() â m_services.get<ConfigCoreService>()
3. Replace VNoteX::getInst().getNotebookMgr() â m_services.get<NotebookCoreService>()
4. Add ServiceLocator &p_services constructor parameter, store as m_services
5. Add to appropriate CMakeLists.txt
CI
GitHub Actions workflows in .github/workflows/: ci-win.yml, ci-linux.yml, ci-macos.yml. Trigger on push/PR to master. Windows builds use Ninja + MSVC 2022 with Qt 6.8.3.
README.md
VNote
!CI-Windows !CI-Linux !CI-MacOS
A pleasant note-taking platform.
For more information, please visit VNote's Home Page.
Description
VNote is a Qt-based, free and open source note-taking application, focusing on Markdown now. VNote is designed to provide a pleasant note-taking platform with excellent editing experience.
VNote is NOT just a simple editor for Markdown. By providing notes management, VNote makes taking notes in Markdown simpler. In the future, VNote will support more formats besides Markdown.
Utilizing Qt, VNote could run on Linux, Windows, and macOS.
!Main
Downloads
Continuous builds on
master branch could be found at the Continuous Build release.Latest stable builds could be found at the latest release. Alternative download services are available:
* Tianyi Netdisk
* Baidu Netdisk
Supports
* GitHub Issues;
* Email:
tamlokveer at gmail.com;* Telegram;
* WeChat Public Account: vnotex;
Thank users who donated to VNote!
Development
After cloning the repository, run the initialization script to set up your development environment:
Linux/macOS:
bash scripts/init.shWindows:
scripts\init.cmdThis script will:
* Initialize and update all git submodules
* Install pre-commit hooks for automatic code formatting with clang-format
* Set up the vtextedit submodule pre-commit hook
For more development guidelines, see AGENTS.md.
License
VNote is licensed under GNU LGPLv3. Code base of VNote could be used freely by VNoteX.