vxcore is a cross-platform C/C++ library providing notebook management functionality for VNote. It offers a stable C ABI for embedding in desktop (Qt), iOS (Swift), and Android (Kotlin) applications.
Key Features: Notebook management, folder/file operations, tag system, full-text search, JSON-based configuration.
# Configure
cmake -B build -DVXCORE_BUILD_TESTS=ON
# Build
cmake --build build
# Run all tests
ctest --test-dir build -C Debug # Windows
ctest --test-dir build # Unix
# Run single test module
ctest --test-dir build -C Debug -R test_core
ctest --test-dir build -C Debug -R test_notebook
ctest --test-dir build -C Debug -R test_folder
ctest --test-dir build -C Debug -R test_search
ctest --test-dir build -C Debug -R test_db
# Run with verbose output
ctest --test-dir build -C Debug -V- Each module has its own test executable:
test_core,test_notebook,test_folder,test_search,test_db, etc. - Individual test cases tracked within each module's
main() - Test macros defined in
tests/test_utils.h:ASSERT,ASSERT_EQ,ASSERT_NE,ASSERT_TRUE,ASSERT_FALSE,ASSERT_NULL,ASSERT_NOT_NULL,RUN_TEST - Test Mode: All tests call
vxcore_set_test_mode(1)to isolate test data- Enabled: Uses
%TEMP%\vxcore_test(Windows) or/tmp/vxcore_test(Unix) - Disabled: Uses real AppData paths (
%APPDATA%\VNote,%LOCALAPPDATA%\VNote) - CLI tools do NOT enable test mode (use production paths)
- Enabled: Uses
- Language: C++17 with C ABI for public API
- Formatting: Use
.clang-formatbased on Google style (indent 2 spaces, 100 col limit, pointer alignment right) - Headers: Sort includes; public API in
include/vxcore/, implementation insrc/ - File Format: Unix line endings
| Element | Convention | Examples |
|---|---|---|
| C API functions | snake_case |
vxcore_context_create, vxcore_notebook_open |
| Types (classes/structs/enums) | PascalCase |
NotebookManager, VxCoreError, FolderConfig |
| Functions/Methods | PascalCase |
GetNotebook(), CreateFolder(), ToJson() |
| Variables (local/global) | snake_case |
notebook_id, root_folder, out_config_json |
| Class data members | snake_case_ (trailing underscore) |
config_, notebooks_, folder_manager_ |
| Struct data members | snake_case (no trailing underscore) |
assets_folder, created_utc, parent_id |
| Constants | kPascalCase |
kMaxPathLength, kConfigFileName |
| Enumerators | kPascalCase |
kSuccess, kTrace, kDebug |
| Macros | UPPER_CASE |
VXCORE_API, RUN_TEST, VXCORE_LOG_INFO |
| Namespaces | snake_case |
vxcore, vxcore::db |
- JSON keys: Always use
camelCase(e.g.,createdUtc,modifiedUtc,assetsFolder,rootFolder) - C++ struct members: Use
snake_case(e.g.,created_utc,modified_utc,assets_folder) - Rationale: User-facing files (config.json, session.json) follow JavaScript conventions
- Return
VxCoreErrorcodes from C API functions - Check null pointers; use
(void)paramfor unused parameters - Caller frees strings with
vxcore_string_free() - Context owns handles; destroy context to free all resources
- Use
VXCORE_APImacro for exports; Windows DLL-safe - No Qt dependencies in core library
- Namespaces: C++ code in
namespace vxcore; close with// namespace vxcore
vxcore/
├── include/vxcore/ # Public C API headers
│ ├── vxcore.h # Main API (context, notebook, folder, file, tag, search)
│ ├── vxcore_types.h # Error codes, handles, version struct
│ └── vxcore_log.h # Logging API
│
├── src/
│ ├── api/ # C API implementation layer
│ │ ├── vxcore_api.cpp # Context, version, test mode
│ │ ├── vxcore_notebook_api.cpp # Notebook operations
│ │ ├── vxcore_folder_api.cpp # Folder/file operations
│ │ ├── vxcore_tag_api.cpp # Tag operations
│ │ ├── vxcore_search_api.cpp # Search operations
│ │ ├── api_utils.h # API helper utilities
│ │ ├── error_handler.h/.cpp # Error handling utilities
│ │ └── handle_manager.h/.cpp # Handle management
│ │
│ ├── core/ # Core C++ business logic
│ │ ├── context.h # VxCoreContext: owns ConfigManager + NotebookManager
│ │ ├── config_manager.h/.cpp # VxCoreConfig + VxCoreSessionConfig management
│ │ ├── vxcore_config.h/.cpp # Application config (vxcore.json)
│ │ ├── vxcore_session_config.h/.cpp # Session config (session.json)
│ │ ├── notebook_manager.h/.cpp # Notebook lifecycle (create, open, close, list)
│ │ ├── notebook.h/.cpp # Notebook base class, NotebookConfig, NotebookRecord, TagNode
│ │ ├── bundled_notebook.h/.cpp # Bundled notebook (config in vx_notebook/config.json)
│ │ ├── raw_notebook.h/.cpp # Raw notebook (config in session only)
│ │ ├── folder_manager.h # Abstract folder/file operations interface
│ │ ├── bundled_folder_manager.h/.cpp # Folder ops for bundled notebooks
│ │ ├── raw_folder_manager.h/.cpp # Folder ops for raw notebooks
│ │ └── folder.h/.cpp # FolderConfig, FolderRecord, FileRecord
│ │
│ ├── db/ # SQLite database layer
│ │ ├── db_manager.h/.cpp # Database lifecycle, schema, transactions
│ │ ├── db_schema.h # Schema definitions (tables, indexes, FTS5)
│ │ ├── file_db.h/.cpp # File/folder CRUD operations
│ │ ├── tag_db.h/.cpp # Tag CRUD and queries
│ │ └── sync_manager.h/.cpp # Filesystem ↔ database synchronization
│ │
│ ├── search/ # Search subsystem
│ │ ├── search_manager.h/.cpp # Search orchestration
│ │ ├── search_backend.h # ISearchBackend interface
│ │ ├── simple_search_backend.h/.cpp # Built-in search implementation
│ │ ├── rg_search_backend.h/.cpp # Ripgrep integration
│ │ ├── search_query.h/.cpp # SearchQuery, SearchScope, SearchOption
│ │ └── search_file_info.h/.cpp # SearchFileInfo struct
│ │
│ ├── platform/ # Platform-specific code
│ │ ├── path_provider.h/.cpp # AppData, LocalData paths per platform
│ │ └── process_utils.h/.cpp # External process execution (for rg)
│ │
│ └── utils/ # General utilities
│ ├── utils.h/.cpp # GenerateUUID(), GetCurrentTimestampMillis(), HasFlag()
│ ├── file_utils.h/.cpp # CleanPath(), ConcatenatePaths(), LoadJsonFile()
│ ├── string_utils.h/.cpp # ToLowerString(), MatchesPattern(), exclude patterns
│ └── logger.h/.cpp # VXCORE_LOG_* macros, Logger singleton
│
├── cli/ # Command-line interface
│ ├── main.cpp # Entry point, command dispatch
│ ├── args.h/.cpp # Argument parsing
│ ├── notebook_cmd.h/.cpp # notebook subcommand
│ ├── tag_cmd.h/.cpp # tag subcommand
│ ├── config_cmd.h/.cpp # config subcommand
│ └── json_helpers.h/.cpp # JSON formatting utilities
│
├── tests/ # Test executables
│ ├── test_utils.h # Test macros and helpers
│ ├── test_core.cpp # Context, config tests
│ ├── test_notebook.cpp # Notebook CRUD tests
│ ├── test_folder.cpp # Folder/file operation tests
│ ├── test_search.cpp # Search tests
│ ├── test_db.cpp # Database layer tests
│ └── ...
│
├── third_party/ # External dependencies (DO NOT MODIFY)
│ ├── nlohmann/json.hpp # JSON library
│ └── sqlite/ # SQLite amalgamation
│
└── data/
└── vxcore.json # Default configuration template
┌─────────────────────────────────────────────────┐
│ C API Layer (include/vxcore/, src/api/) │ ← Stable ABI for FFI
├─────────────────────────────────────────────────┤
│ Core Layer (src/core/) │ ← Business logic
├─────────────────────────────────────────────────┤
│ Database Layer (src/db/) │ ← SQLite metadata
├──────────────────────┬──────────────────────────┤
│ Platform (src/platform/) │ Utils (src/utils/)│ ← Cross-cutting concerns
└──────────────────────┴──────────────────────────┘
- Context-based API: All operations go through
VxCoreContextHandle - Opaque handles: C API uses opaque pointers for type safety
- JSON boundaries: All complex data crosses C ABI as JSON strings
- Two notebook types:
- Bundled: Config stored in
<root>/vx_notebook/config.json, metadata in<root>/vx_notebook/ - Raw: Config stored in session config only, metadata in local data folder
- Bundled: Config stored in
- FolderManager abstraction:
BundledFolderManagerandRawFolderManagerimplement different storage strategies - Search backends: Pluggable via
ISearchBackendinterface (ripgrep, simple built-in)
NotebookManageroperations are NOT thread-safe; caller must synchronizeDbManager,FileDb,TagDbare NOT thread-safe; designed for single-threaded use per notebookLoggeris thread-safe (uses mutex)
User Code
│
▼
C API (vxcore_*)
│
▼
VxCoreContext
├── ConfigManager (VxCoreConfig, VxCoreSessionConfig)
└── NotebookManager
└── Notebook (Bundled/Raw)
├── NotebookConfig (id, name, tags, metadata)
├── FolderManager (folder/file operations)
│ └── DbManager + FileDb + TagDb
└── SearchManager (search operations)
└── ISearchBackend (rg/simple)
| Aspect | Bundled | Raw |
|---|---|---|
| Config location | <root>/vx_notebook/config.json |
Session config only |
| Metadata folder | <root>/vx_notebook/ |
<local_data>/notebooks/<id>/ |
| Database location | <metadata_folder>/metadata.db |
<metadata_folder>/metadata.db |
| Portable | Yes (self-contained) | No (external metadata) |
- Always use
CleanPath()orCleanFsPath()to normalize paths - Paths use forward slashes internally (even on Windows)
- Relative paths within notebook are relative to notebook root
- Use
ConcatenatePaths()to join path components
src/utils/utils.h:GenerateUUID(),GetCurrentTimestampMillis(),HasFlag()src/utils/file_utils.h:CleanPath(),LoadJsonFile(),ConcatenatePaths(),SplitPath(),RelativePath()src/utils/string_utils.h:ToLowerString(),MatchesPattern(),MatchesPatterns()src/utils/logger.h:VXCORE_LOG_TRACE/DEBUG/INFO/WARN/ERROR/FATAL
#include "utils/logger.h"
VXCORE_LOG_INFO("Opening notebook: %s", path.c_str());
VXCORE_LOG_ERROR("Failed to open database: %s", db_path.c_str());- Declare in
include/vxcore/vxcore.h - Implement in appropriate
src/api/vxcore_*_api.cpp - Add tests in
tests/test_*.cpp
- Implement in
src/core/ - Expose through existing managers or create new manager
- Add C API wrapper in
src/api/ - Add tests
#include <nlohmann/json.hpp>
// Parsing
nlohmann::json j = nlohmann::json::parse(json_string);
auto config = NotebookConfig::FromJson(j);
// Serializing
nlohmann::json j = config.ToJson();
std::string json_string = j.dump();VxCoreError MyFunction(const char* input, char** output) {
if (!input || !output) {
return VXCORE_ERR_NULL_POINTER;
}
try {
// ... implementation ...
*output = strdup(result.c_str());
return VXCORE_OK;
} catch (const std::exception& e) {
VXCORE_LOG_ERROR("MyFunction failed: %s", e.what());
return VXCORE_ERR_UNKNOWN;
}
}