Implement a loader function to load a complete SyntaxHighlighting engine from an INI file Enable compile_commands.json and improve syntax handling - #88
Conversation
WalkthroughThis PR enables compile_commands.json in CMake, adjusts executable path resolution, converts SyntaxHighlighting to take ownership of SyntaxDefinition with Create/Destroy APIs, adds a loader to read syntax .ini files with detailed errors, adds null guards in bindings, and updates tests accordingly. Changes
Sequence Diagram(s)sequenceDiagram
participant Caller
participant Loader as SyntaxHighlighting_LoadFromFile
participant File as File I/O
participant Parser as IniParser
participant DefBuilder as SyntaxDefinition_FromTable
participant HL as SyntaxHighlighting_Create
Caller->>Loader: LoadFromFile(format, error)
rect rgb(200, 220, 255)
Note over Loader: Validation & Initialization
Loader->>Loader: Initialize error state<br/>Check format != NULL
end
rect rgb(220, 255, 220)
Note over Loader: File Read Phase
Loader->>File: Open data/syntax/<format>.ini
alt File Open Success
Loader->>File: Read file content
alt Read Success
File-->>Loader: Content buffer
else Read/IO Error
Loader->>Loader: Set error (FILE_READ_ERROR)
Loader-->>Caller: NULL
rect rgb(255, 200, 200)
Note over Loader: Error path
end
end
else File Not Found
Loader->>Loader: Set error (FILE_NOT_FOUND)
Loader-->>Caller: NULL
rect rgb(255, 200, 200)
Note over Loader: Error path
end
end
end
rect rgb(255, 240, 200)
Note over Loader: Parse Phase
Loader->>Parser: Parse INI content to Table
alt Parse Success
Parser-->>Loader: Table
else Parse Error
Loader->>Loader: Copy parse error to error.parsing_error
Loader->>Loader: Set error (PARSE_ERROR)
Loader-->>Caller: NULL
rect rgb(255, 200, 200)
Note over Loader: Error path
end
end
end
rect rgb(240, 255, 240)
Note over Loader: Definition Build Phase
Loader->>DefBuilder: SyntaxDefinition_FromTable(Table)
alt Definition Success
DefBuilder-->>Loader: SyntaxDefinition
else Definition Error
Loader->>Loader: Copy def error to error.def_error
Loader->>Loader: Set error (DEFINITION_ERROR)
Loader-->>Caller: NULL
rect rgb(255, 200, 200)
Note over Loader: Error path
end
end
end
rect rgb(220, 240, 255)
Note over Loader: Create Phase
Loader->>HL: SyntaxHighlighting_Create(SyntaxDefinition)
HL-->>Loader: SyntaxHighlighting*
end
Loader-->>Caller: SyntaxHighlighting* (ownership transferred)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 8
🧹 Nitpick comments (9)
CMakeLists.txt (1)
8-9: Enabling compile_commands.json looks goodConsider using uppercase ON for consistency and, if your build dir ≠ source dir, add a post-config step to copy/symlink compile_commands.json to the source root so editors find it.
src/syntax/highlighting.c (1)
118-121: Add null‑guard to Destroy (optional)Defensive free if API might receive NULL.
Apply:
-void SyntaxHighlighting_Destroy(SyntaxHighlighting *hl) { - SyntaxHighlighting_Deinit(hl); - free(hl); -} +void SyntaxHighlighting_Destroy(SyntaxHighlighting *hl) { + if (!hl) return; + SyntaxHighlighting_Deinit(hl); + free(hl); +}src/syntax/highlighting.h (2)
85-91: Document ownership prominently in InitConsider adding “def must be heap‑allocated; sh takes ownership and will destroy it.”
95-105: Create/Destroy API addition looks goodSuggest documenting that Destroy also frees the owned def.
src/syntax/loader.h (3)
4-6: Include what you use: add the header that declares SyntaxDefinitionErrorThis header uses SyntaxDefinitionError but doesn’t include its declaration explicitly. Relying on transitive includes is brittle.
Apply:
#include "highlighting.h" #include "common/iniparser.h" +#include "definition.h"
25-40: Fix docs: typos, type name, path, and clarify error contractSeveral typos and one wrong type name; also clarify that
errormust be non-NULL./** * @brief Load a syntax definition and create the highlight engine. * - * Load the syntax definition for `format` from data/sytnax/<format>.ini - * (from inside a project's folder) and create the `SyntaxHighlight` instance. + * Load the syntax definition for `format` from data/syntax/<format>.ini + * (from inside the project's folder) and create the `SyntaxHighlighting` instance. * * @param format Format to load (something like "ini", "md"). - * @param error Will be set in the case of an error and need to be deinitialized by the caller. + * @param error Out-parameter for error details. Must not be NULL. When an error occurs, + * it will be populated and must be deinitialized by the caller. * @returns - * The newly created SyntaxHighlighting Instance (ownership transfers to the caller). - * NULL there is definition file or if an error occured. - * In the case of an error `error` will be set and need to be deinitialized by the caller. + * The newly created SyntaxHighlighting instance (ownership transfers to the caller), + * or NULL if no definition file exists or if an error occurred. + * On error, `error` will be populated and must be deinitialized by the caller. * - * Note theat `format` needs to be exactly the same as the filename. + * Note that `format` needs to be exactly the same as the filename. * The convention is to use lower case. */
16-20: Public API coupling to ParsingErrorExposing ParsingError in a public error struct ties this API to iniparser’s internal layout. Consider a stable copy (your own error struct) and translate fields to it.
src/syntax/loader.c (2)
6-11: Make deinit robust to NULL and double-freeGuard NULL, and null out the message after free to avoid accidental double-free on reuse.
void SyntaxHighlightingLoaderError_Deinit(SyntaxHighlightingLoaderError *error) { - SyntaxDefinitionError_Deinit(&error->def_error); - if (error->parsing_error.message) { - free(error->parsing_error.message); - } + if (!error) return; + SyntaxDefinitionError_Deinit(&error->def_error); + if (error->parsing_error.message) { + free(error->parsing_error.message); + error->parsing_error.message = NULL; + } + error->code = SYNTAX_LOADER_NO_ERROR; }
47-51: Review comment is valid but describes preventive refactoring, not a current bugThe ParsingError struct contains only three fields:
int line,int column, andchar *message(one pointer). The current code correctly works because:
- Line/column are POD fields—safe to shallow copy
- Message is explicitly deep-copied via
strdup()beforeIniParser_Deinit()is calledThe review's concern is valid from a maintenance perspective: if a future pointer field is added to ParsingError without updating this code, it would dangle. The suggested refactor improves defensiveness and clarity.
Additionally, there's a minor inefficiency:
IniParser_GetError()is called twice on consecutive lines when once would suffice.The suggested approach of copying only POD fields and explicitly handling pointer fields is sound defensive programming.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
CMakeLists.txt(1 hunks)src/io/file.c(1 hunks)src/io/file.h(1 hunks)src/syntax/highlighting.c(2 hunks)src/syntax/highlighting.h(1 hunks)src/syntax/loader.c(1 hunks)src/syntax/loader.h(1 hunks)src/syntax/textlayoutbindings.c(1 hunks)tests/test_syntax_highlighting.c(0 hunks)tests/test_syntax_loader.c(1 hunks)tests/test_syntax_textlayoutbindings.c(0 hunks)
💤 Files with no reviewable changes (2)
- tests/test_syntax_highlighting.c
- tests/test_syntax_textlayoutbindings.c
🧰 Additional context used
🧬 Code graph analysis (6)
src/syntax/highlighting.c (1)
src/syntax/definition.c (1)
SyntaxDefinition_Destroy(372-386)
src/io/file.c (1)
src/common/config.c (1)
Config_GetExePath(89-91)
src/syntax/highlighting.h (1)
src/syntax/highlighting.c (4)
SyntaxHighlighting_Init(93-96)SyntaxHighlighting_Deinit(98-107)SyntaxHighlighting_Create(109-116)SyntaxHighlighting_Destroy(118-121)
src/syntax/loader.c (5)
src/syntax/definition.c (2)
SyntaxDefinitionError_Deinit(36-38)SyntaxDefinition_FromTable(324-370)src/io/file.c (3)
File_OpenProjectFile(122-128)File_Read(169-193)File_Close(130-141)src/common/iniparser.c (5)
IniParser_Init(362-367)IniParser_SetText(389-391)IniParser_Parse(401-421)IniParser_GetError(397-399)IniParser_Deinit(369-372)src/common/table.c (1)
Table_Destroy(223-229)src/syntax/highlighting.c (1)
SyntaxHighlighting_Create(109-116)
src/syntax/loader.h (1)
src/syntax/loader.c (2)
SyntaxHighlightingLoaderError_Deinit(6-11)SyntaxHighlighting_LoadFromFile(14-68)
tests/test_syntax_loader.c (3)
src/common/config.c (3)
Config_GetExePath(89-91)Config_Init(40-49)Config_Deinit(51-58)src/syntax/loader.c (2)
SyntaxHighlighting_LoadFromFile(14-68)SyntaxHighlightingLoaderError_Deinit(6-11)src/syntax/highlighting.c (1)
SyntaxHighlighting_Destroy(118-121)
🪛 Clang (14.0.6)
src/io/file.h
[error] 19-19: 'limits.h' file not found
(clang-diagnostic-error)
🔇 Additional comments (9)
src/io/file.c (1)
70-76: Excellent refactoring for safer path resolution.The change from in-place buffer usage to separate buffers for
realpathanddirnameimproves both clarity and safety. The new approach correctly handlesdirname()'s POSIX behavior (may modify input buffer and return pointer to internal storage or modified buffer). The returned pointer is used immediately within its valid scope, making this implementation safe.src/syntax/highlighting.c (2)
102-105: Deinit now frees hl->def (breaking change)Confirm no external owner frees def separately.
If any legacy code used borrowed defs, update it to not destroy def.
93-97: Ownership transfer verified—no double-free patterns detectedAll call sites properly call
SyntaxHighlighting_Deinitafter passingdeftoSyntaxHighlighting_Init. The ownership transfer is correctly managed:Deinittakes ownership and destroysdefviaSyntaxDefinition_Destroy. No cases found wheredefis destroyed twice or accessed after transfer.src/syntax/highlighting.h (1)
76-83: Ownership change is clearField switched to owned SyntaxDefinition*. Matches impl.
src/syntax/loader.h (1)
41-41: Document and enforce non-NULLerrorThe implementation dereferences
error. Make non-NULL a documented precondition (see doc fix) and also enforce it in code.Would you like me to add an assertion/guard in the implementation as shown in my loader.c diff below?
src/syntax/loader.c (4)
33-39: Good cleanup on read failureFile_Close is called on read error before returning. Nice.
58-64: OK: Definition error path cleans up Table and sets codeThis branch looks correct and leak-free.
66-68: Return ownership clarityReturning SyntaxHighlighting_Create(def) correctly transfers ownership; ensure callers destroy via SyntaxHighlighting_Destroy.
Do tests cover destroy on both success and failure paths?
23-31: Function appears to be dead code;formatcannot receive user input in current applicationAfter comprehensive codebase analysis,
SyntaxHighlighting_LoadFromFileis only called from test files (5 calls intests/test_syntax_loader.cwith hardcoded strings). No calls exist in production code—includingsrc/main.c, app initialization, or editor modules. The main application flow parses a filename argument but never attempts to load syntax highlighting, making the function unreachable with user-controlled input.The
snprintftruncation check remains good defensive programming practice. However, the path traversal concern is currently theoretical sinceformatcannot originate from user input.Verify whether this function is intended for future use and confirm the planned source of the
formatparameter.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
src/syntax/loader.c (1)
1-4: Still missing<limits.h>forPATH_MAX.The prior review flagged that
PATH_MAX(used at line 32) requires<limits.h>, but this header was not added. Without it, builds may fail on stricter toolchains.Apply this diff:
#include "loader.h" #include <string.h> #include <stdio.h> // snprintf +#include <limits.h> // PATH_MAX #include "io/file.h"
🧹 Nitpick comments (2)
src/syntax/loader.c (2)
12-17: Add NULL guard for defensive programming.While the current usage always calls
InitbeforeDeinit, this is a public API and should handle NULL gracefully.Apply this diff:
void SyntaxHighlightingLoaderError_Deinit(SyntaxHighlightingLoaderError *error) { + if (!error) { + return; + } SyntaxDefinitionError_Deinit(&error->def_error); if (error->parsing_error.message) { free(error->parsing_error.message); } }
65-76: Consider documenting ownership transfer.The code correctly creates the engine from
def(line 75), and based on the API contractSyntaxHighlighting_Createtakes ownership. However, the ownership transfer is implicit, and there's no NULL check afterCreate.While the current implementation is correct (since
SyntaxHighlighting_CreatecallslogFatalon allocation failure), consider adding a comment to clarify ownership:Table_Destroy(table); - // 5. create the highlighting engine + // 5. create the highlighting engine (transfers ownership of def) return SyntaxHighlighting_Create(def); }
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/syntax/loader.c(1 hunks)src/syntax/textlayoutbindings.c(1 hunks)tests/test_syntax_loader.c(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- src/syntax/textlayoutbindings.c
- tests/test_syntax_loader.c
🧰 Additional context used
🧬 Code graph analysis (1)
src/syntax/loader.c (5)
src/syntax/definition.c (2)
SyntaxDefinitionError_Deinit(36-38)SyntaxDefinition_FromTable(324-370)src/io/file.c (3)
File_OpenProjectFile(122-128)File_Read(169-193)File_Close(130-141)src/common/iniparser.c (5)
IniParser_Init(362-367)IniParser_SetText(389-391)IniParser_Parse(401-421)IniParser_GetError(397-399)IniParser_Deinit(369-372)src/common/table.c (1)
Table_Destroy(223-229)src/syntax/highlighting.c (1)
SyntaxHighlighting_Create(109-116)
🔇 Additional comments (3)
src/syntax/loader.c (3)
6-9: LGTM—clean initialization.The
memsetzero-initializes all fields (includingdef_error), addressing the prior critical concern about uninitialized state.
20-29: LGTM—proper validation and initialization.The NULL guard for
error(lines 21-23) and zero-initialization viaInit(line 24) correctly address the prior critical issue.
31-47: LGTM—clean file handling.File open/read/close operations are properly sequenced, with
File_Closecorrectly called in both success and error paths.
* add String_Split() and String_Trim() with tests * add example syntax definition * Feat/Implement Syntax Definitions (#84) * add SyntaxBlockDef and SyntaxDefinition declarations * add TableIterator (#79) * add TableIterator * change include that provides ssize_t * add additional tests * make current slot pointer const * include stdbool.h for bool * Add table iteration API and improve parsing robustness (#83) * add TableIterator (#79) * add TableIterator * change include that provides ssize_t * add additional tests * make current slot pointer const * include stdbool.h for bool * WIP: implement definition loader * add Table_GetUsage() * allow ':' in INI file key names * fix location of tests * fix typo in Doxygen comment * add NULL guard to String_Take() * Add early-exit guards to table lookup functions (#80) * Fix bug in reading operations on an empty table * add check for empty table also to Table_Delete() * add functiond to create SyntaxDefinition_FromTable() with tests. More tests needed * additional tests (still not enough) * fix: free correct regex in regex_end branch in SyntaxBlockDef_FromTable() * fix: wrong numbe of arguments in String_Format() call in SymtaxBlockDef_FromTable() * add explanation * fix correct recognition of root block * fix memory lealk * add NULL guard for strdup in init_definition() * fix last fix * add additional test * add documentation * Feat/Syntax Highlighting: Add module to generate Highlighting information (#85) * add Stack_Copy() and Stack_IsEmpty() * fix: return copy in Stack_Copy() * implement syntax highlighting * add Table_CreateCustom() and Table_CreatePtr() * fix minor typing bugs * add Stack_Create(), Stack_Destroy() * fix but in find_first_child to actually return the child with the first occurence * automatically add patterns to end only_start blocks and to start/end root * fix memory leak produced in last commit * fix tests * fix bug in SyntaxHighllighting_HighlightString(): check if child or block end comes first * add basic tests * use root block it open_blocks parameter is NULL in SyntaxHighlighting_HighlightString() * add random tests * handle src->capacity == 0 in Stack_Copy() * add NULL pointer guard before using the key_free_func() function pointer in the Table module * fix error message for end_regex compilation error in SyntaxBlockDef_FromTable() * correct inlcudes * fix typo * add missing includes * change examples in documentation * change "key == NULL" to "!key" for non pointer keys * do not shadow parameter match in find_first_block() * change first parameter name in SyntaxHighlighting_HighlightString() for consitency * Cache regex matches and add ends_on option for Syntax definitions (#86) * add const to parameter if function does not modify it. add Buffer_Has_Space(), Buffer_Clear() * cache regex results for better performance * add "ends_on" (INI) property to SyntaxBlockDef * implement ends_on in the SyntaxHighlight modul * remove the check if the ends_on block is allowed inside the surrounding block. this leads to more flexibility and better performance * add additional (but just a single) test for the new feature * add Stack_CopyTo() * save open_blocks_at_begin and open_blocks_at_end to SyntaxHighlightingString instances ins SyntaxHighlighting_HighlightString() * Add Syntax Highlighting binding for TextBuffer (#87) * add TableIterator (#79) * add TableIterator * change include that provides ssize_t * add additional tests * make current slot pointer const * include stdbool.h for bool * Add early-exit guards to table lookup functions (#80) * Fix bug in reading operations on an empty table * add check for empty table also to Table_Delete() * Add CodeRabbit configuration template Added a comprehensive configuration template for CodeRabbit, including global settings, review settings, chat configurations, knowledge base settings, and code generation options. * add SyntaxHighlightingBinding to connect SyntaxHighlighting with the TextBuffer/TextLayout * fix some obvious bugs in SyntaxHighlighingBinding * fix memory leak * add basic test * add Stack_Size() * rename test function * add Stack_CopyTo() * save open_blocks_at_begin and open_blocks_at_end to SyntaxHighlightingString instances ins SyntaxHighlighting_HighlightString() * adept code to the changed SyntaxHighlighingString scheme * improve tests * Compare the open_blocks_at_begin with the open_blocks parameter for an early exit int SyntaxHighlighting_HighlightString() * add testcases and improve test framework's flexibility * fix coderabbit config * fix resizing in Stack_CopyTo() * add NULL guard to SyntaxHighlighting_HighlightString() * change multiline string to valid C string * change multiline strings to valid C strings * set shs->tags_capacity correctly in SyntaxHighlioghtingString_Create() * make argv0 available through Config * Add File_Exits(), File_OpenConfig() and File_OpenProjectFile() * change defautl width * fix wrong function calls * use new File_LoadConfig() function * remove unused variable * check if snprintf() truncated the path * fix function declaration of File_OpenProjectFile() * Implement a loader function to load a complete SyntaxHighlighting engine from an INI file Enable compile_commands.json and improve syntax handling (#88) * propagate PATH_MAX by file.h * create compile_commands.json (for correct using include paths in vscode) * add create and destroy functions to SyntaxHighlighting * SyntaxHighlighting now takes the ownership of the used SyntaxDefinition * must not destroy SyntaxDefinition anymore since this is handled by SyntaxHighlighting * fix bug in find_project_file() * implement the SyntaxHighlighting_LoadFromFile() function and tests * add NULL guard * Initialize error properly in SyntaxHighlighting_LoadFromFile() * guard againsst line == NULL and handle last_line == NULL in SyntaxHighlightingBinding_Update() * fix bug in concat_paths() * add test_definition_error to TEST_LIST * Integrate SyntaxHighlighting to the editor (#89) * wip * link to the data directory in the build directory * example syntax definitions * massive changes to get syntax highlighting working... need to optimization and better organisation, lot of work arounds * comment out TESTFILE definition * destroy SyntaxHighlighting instance properly * fix Table_Get() call in draw_visual_line() to use the correct key * improve highlighting * add Config_SetSyntax(), Config_GetSyntax() * use getopt() to parse cmd arguments, take syntax type from cmd arguments * Trigger a full SyntaxHighlighting update once in the beginning * add hint that byte offset is used * update screenshot * improve markdown highlighting * remove TESTFILE debugging stuff * handle the case that no highlighting is selected * deinitialize IniParser at ealry exit if c == NULL in Config_LoadIni() * remove double deinitialization of TextSelection in editor_destroy() * fix parse_arguments() and update print_help() * fix critical bug in Table_Set/Get(): change state of tombstones when reusing them * anchor section block start to newline * fix comment * fix off-by-one bug in Buffer_HasSpace() * guard against NULL in SyntaxHighlightingBinding_UpdateAll() * update syntax definitions * fix off-by-one bug in SyntaxHighlightingString_AddTag() * fix potential int overflow * add comment * minor change to const correctness in cpy_ptr * update readme * fix intendation
Summary by CodeRabbit
New Features
Bug Fixes
Refactor
Tests
Chores