Skip to content

Commit

Permalink
Support for overriding the syntax highlighting settings (#348)
Browse files Browse the repository at this point in the history
* Writing support for overrides of highlighting settings

* Automatically creating the "SyntaxHighlighting" overrides directory and passing this path to FileSettingsStorage. Updated some APIs to use std::filesystem::path instead of std::string.

* Reloading the override settings as they change

* Added notes about how overriding of the highlighting settings works.
  • Loading branch information
mikekazakov authored Jul 27, 2024
1 parent 493d1f7 commit c56ca9a
Show file tree
Hide file tree
Showing 10 changed files with 308 additions and 44 deletions.
4 changes: 2 additions & 2 deletions Docs/SyntaxHighlighting.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@ Here's an example of such settings file:

In addition to the styles mapping, the settings file also provides the name of the lexer to be used, lists of keywords, and lexer properties.

These JSON files are all located in the application directory `SyntaxHighlighting`, which is currently non-modifiable. In the future, Nimble Commander will support overriding with files placed in the `~/Library/Application Support/...` directory.
These JSON files are located in the application's `SyntaxHighlighting` directory, shipped with the application. This directory also contains the `Main.json` file, which defines the list of known languages, their file masks, and the filenames of the settings for each language.

This directory also contains the `Main.json` file, which defines the list of known languages, their file masks, and the filenames of the settings for each language.
Nimble Commander supports overriding these settings with files placed in the `~/Library/Application Support/Nimble Commander/SyntaxHighlighting` directory. Any file will first be looked for in the `Application Support` directory, and if not found, in the application directory. Changes in the overrides directory will be automatically picked up by Nimble Commander, and the next time the Viewer is shown, the updated settings will be used.

## Helper Tool

Expand Down
4 changes: 2 additions & 2 deletions Source/Config/include/Config/FileOverwritesStorage.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2018-2021 Michael Kazakov. Subject to GNU General Public License version 3.
// Copyright (C) 2018-2024 Michael Kazakov. Subject to GNU General Public License version 3.
#pragma once

#include "OverwritesStorage.h"
Expand All @@ -12,7 +12,7 @@ namespace nc::config {
class FileOverwritesStorage : public OverwritesStorage
{
public:
FileOverwritesStorage(std::string_view _file_path);
FileOverwritesStorage(const std::filesystem::path &_file_path);
FileOverwritesStorage(const FileOverwritesStorage &) = delete;
~FileOverwritesStorage();

Expand Down
6 changes: 3 additions & 3 deletions Source/Config/source/FileOverwritesStorage.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2018-2022 Michael Kazakov. Subject to GNU General Public License version 3.
// Copyright (C) 2018-2024 Michael Kazakov. Subject to GNU General Public License version 3.
#include "FileOverwritesStorage.h"
#include "Log.h"
#include <sys/stat.h>
Expand All @@ -16,10 +16,10 @@ using utility::FSEventsDirUpdate;
static std::optional<std::string> Load(const std::string &_filepath);
static time_t ModificationTime(const std::string &_filepath);

FileOverwritesStorage::FileOverwritesStorage(std::string_view _file_path) : m_Path(_file_path)
FileOverwritesStorage::FileOverwritesStorage(const std::filesystem::path &_file_path) : m_Path(_file_path)
{
Log::Trace(SPDLOC, "Created storage with path: {}", _file_path);
auto parent_path = std::filesystem::path{std::string{_file_path}}.parent_path();
auto parent_path = _file_path.parent_path();
Log::Trace(SPDLOC, "Setting observation for directory: {}", parent_path);
m_DirObservationTicket =
FSEventsDirUpdate::Instance().AddWatchPath(parent_path.c_str(), [this] { OverwritesDirChanged(); });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include <VFS/VFS_fwd.h>
#include <Cocoa/Cocoa.h>
#include <filesystem>

@class NCConfigObjCBridge;
@class NCMainWindowController;
Expand Down Expand Up @@ -86,18 +87,18 @@ class NativeHost;
* Support dir, ~/Library/Application Support/Nimble Commander/.
* Is in Containers for Sandboxes versions
*/
@property(nonatomic, readonly) const std::string &supportDirectory;
@property(nonatomic, readonly) const std::filesystem::path &supportDirectory;

/**
* By default this dir is ~/Library/Application Support/Nimble Commander/Config/.
* May change in the future.
*/
@property(nonatomic, readonly) const std::string &configDirectory;
@property(nonatomic, readonly) const std::filesystem::path &configDirectory;

/**
* This dir is ~/Library/Application Support/Nimble Commander/State/.
*/
@property(nonatomic, readonly) const std::string &stateDirectory;
@property(nonatomic, readonly) const std::filesystem::path &stateDirectory;

@property(nonatomic, readonly) NCConfigObjCBridge *config;

Expand Down
26 changes: 19 additions & 7 deletions Source/NimbleCommander/NimbleCommander/Bootstrap/AppDelegate.mm
Original file line number Diff line number Diff line change
Expand Up @@ -226,9 +226,9 @@ @implementation NCAppDelegate {
std::vector<NCMainWindowController *> m_MainWindows;
std::vector<InternalViewerWindowController *> m_ViewerWindows;
nc::spinlock m_ViewerWindowsLock;
std::string m_SupportDirectory;
std::string m_ConfigDirectory;
std::string m_StateDirectory;
std::filesystem::path m_SupportDirectory;
std::filesystem::path m_ConfigDirectory;
std::filesystem::path m_StateDirectory;
std::vector<nc::config::Token> m_ConfigObservationTickets;
upward_flag m_FinishedLaunching;
std::shared_ptr<nc::panel::FavoriteLocationsStorageImpl> m_Favorites;
Expand Down Expand Up @@ -478,19 +478,19 @@ - (void)setupConfigs

g_Config = new nc::config::ConfigImpl(
*config_defaults,
std::make_shared<nc::config::FileOverwritesStorage>(self.configDirectory + "Config.json"),
std::make_shared<nc::config::FileOverwritesStorage>(self.configDirectory / "Config.json"),
std::make_shared<nc::config::DelayedAsyncExecutor>(write_delay),
std::make_shared<nc::config::DelayedAsyncExecutor>(reload_delay));

g_State = new nc::config::ConfigImpl(
*state_defaults,
std::make_shared<nc::config::FileOverwritesStorage>(self.stateDirectory + "State.json"),
std::make_shared<nc::config::FileOverwritesStorage>(self.stateDirectory / "State.json"),
std::make_shared<nc::config::DelayedAsyncExecutor>(write_delay),
std::make_shared<nc::config::DelayedAsyncExecutor>(reload_delay));

g_NetworkConnectionsConfig = new nc::config::ConfigImpl(
"",
std::make_shared<nc::config::FileOverwritesStorage>(self.configDirectory + "NetworkConnections.json"),
std::make_shared<nc::config::FileOverwritesStorage>(self.configDirectory / "NetworkConnections.json"),
std::make_shared<nc::config::DelayedAsyncExecutor>(write_delay),
std::make_shared<nc::config::DelayedAsyncExecutor>(reload_delay));

Expand Down Expand Up @@ -971,8 +971,20 @@ - (IBAction)onMainMenuShowLogs:(id)_sender

- (nc::viewer::hl::SettingsStorage &)syntaxHighlightingSettingsStorage
{
// if the overrides directory doesn't exist - create it. Check it only once per run
static std::once_flag once;
std::call_once(once, [self] {
const std::filesystem::path overrides_dir = self.supportDirectory / "SyntaxHighlighting";
std::error_code ec = {};
if( !std::filesystem::exists(overrides_dir, ec) ) {
std::filesystem::create_directory(overrides_dir, ec);
}
});

[[clang::no_destroy]] static nc::viewer::hl::FileSettingsStorage storage{
[NSBundle.mainBundle pathForResource:@"SyntaxHighlighting" ofType:@""].fileSystemRepresentation, ""};
[NSBundle.mainBundle pathForResource:@"SyntaxHighlighting" ofType:@""].fileSystemRepresentation,
self.supportDirectory / "SyntaxHighlighting"};

return storage;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (C) 2016-2018 Michael Kazakov. Subject to GNU General Public License version 3.
// Copyright (C) 2016-2024 Michael Kazakov. Subject to GNU General Public License version 3.
#pragma once

#include <string>
#include <filesystem>
#include <memory>

class NetworkConnectionsManager;
Expand All @@ -11,9 +11,9 @@ namespace nc {
class AppDelegate
{
public:
static const std::string &ConfigDirectory();
static const std::string &StateDirectory();
static const std::string &SupportDirectory();
static const std::filesystem::path &ConfigDirectory();
static const std::filesystem::path &StateDirectory();
static const std::filesystem::path &SupportDirectory();
static const std::shared_ptr<NetworkConnectionsManager> &NetworkConnectionsManager();
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2016-2020 Michael Kazakov. Subject to GNU General Public License version 3.
// Copyright (C) 2016-2024 Michael Kazakov. Subject to GNU General Public License version 3.
#include "AppDelegateCPP.h"
#include <Utility/PathManip.h>
#include <Utility/StringExtras.h>
Expand All @@ -7,21 +7,21 @@

namespace nc {

const std::string &AppDelegate::ConfigDirectory()
const std::filesystem::path &AppDelegate::ConfigDirectory()
{
return NCAppDelegate.me.configDirectory;
}

const std::string &AppDelegate::StateDirectory()
const std::filesystem::path &AppDelegate::StateDirectory()
{
return NCAppDelegate.me.stateDirectory;
}

const std::string &AppDelegate::SupportDirectory()
const std::filesystem::path &AppDelegate::SupportDirectory()
{
// this is a duplicate of NCAppDelegate.supportDirectory,
// but it has to be here to break down an initialization dependency circle
[[clang::no_destroy]] static const std::string support_dir = [] {
[[clang::no_destroy]] static const std::filesystem::path support_dir = [] {
auto path = NSFileManager.defaultManager.applicationSupportDirectory;
return EnsureTrailingSlash(path.fileSystemRepresentationSafe);
}();
Expand Down
16 changes: 15 additions & 1 deletion Source/Viewer/include/Viewer/Highlighting/FileSettingsStorage.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ class FileSettingsStorage : public SettingsStorage
{
public:
FileSettingsStorage(const std::filesystem::path &_base_dir, const std::filesystem::path &_overrides_dir);
FileSettingsStorage(const FileSettingsStorage &) = delete;
~FileSettingsStorage();
FileSettingsStorage &operator=(const FileSettingsStorage &) = delete;

std::optional<std::string> Language(std::string_view _filename) noexcept override;

Expand All @@ -24,9 +27,20 @@ class FileSettingsStorage : public SettingsStorage
nc::utility::FileMask mask;
};

std::vector<Lang> LoadLangs();
// Loads and parses the contents of the "Main.json" file
std::vector<Lang> LoadLangs(const std::filesystem::path &_path) const;

void ReloadLangs();

void SubscribeToOverridesChanges();
void UnsubscribeFromOverridesChanges();
void OverridesChanged();

std::filesystem::path m_BaseDir;
std::filesystem::path m_OverridesDir;
uint64_t m_OverridesObservationToken = 0;
bool m_Outdated = false;

std::vector<Lang> m_Langs;
robin_hood::unordered_flat_map<std::string,
std::shared_ptr<const std::string>,
Expand Down
Loading

0 comments on commit c56ca9a

Please sign in to comment.