Skip to content

Commit cc96de6

Browse files
committed
feat: command line file loading, font dialog with system fonts, fix ImGui ID conflicts, open file focus
1 parent 748f406 commit cc96de6

3 files changed

Lines changed: 81 additions & 27 deletions

File tree

src/editor_app.cpp

Lines changed: 74 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,8 @@ static void settings_load(AppSettings& s, const std::string& path) {
127127
// ============================================================================
128128
// Constructor / Destructor
129129
// ============================================================================
130-
EditorApp::EditorApp() {
130+
EditorApp::EditorApp(int argc, char* argv[])
131+
: argc_(argc), argv_(argv) {
131132
new_tab(); // Start with one untitled tab
132133
font_size_temp_ = settings_.font_size;
133134
tab_size_temp_ = settings_.tab_size;
@@ -139,11 +140,20 @@ EditorApp::~EditorApp() {
139140
}
140141
}
141142

143+
void EditorApp::load_files_from_args(int argc, char* argv[]) {
144+
for (int i = 1; i < argc; i++) {
145+
open_file(argv[i]);
146+
}
147+
}
148+
142149
// ============================================================================
143150
// Main loop
144151
// ============================================================================
145152
int EditorApp::run() {
146153
init();
154+
155+
// Load files from command line arguments
156+
load_files_from_args(argc_, argv_);
147157

148158
while (running_ && !glfwWindowShouldClose(window_)) {
149159
glfwPollEvents();
@@ -182,6 +192,9 @@ int EditorApp::run() {
182192
void EditorApp::init() {
183193
load_settings();
184194

195+
// Initialize native file dialog
196+
NFD_Init();
197+
185198
glfwInit();
186199
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
187200
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
@@ -225,12 +238,14 @@ void EditorApp::init() {
225238

226239
ed->SetTabSize(settings_.tab_size);
227240
ed->SetShowWhitespaces(settings_.show_spaces);
241+
// Note: TextEditor always shows line numbers (no toggle available in this version)
228242

229243
apply_zoom(tab_idx);
230244
}
231245
}
232246

233247
void EditorApp::shutdown() {
248+
NFD_Quit();
234249
ImGui_ImplOpenGL3_Shutdown();
235250
ImGui_ImplGlfw_Shutdown();
236251
ImGui::DestroyContext();
@@ -305,13 +320,18 @@ void EditorApp::open_file(const std::string& path) {
305320

306321
if (path.empty()) {
307322
nfdchar_t* out_path = nullptr;
308-
nfdresult_t result = NFD_OpenDialog(&out_path, nullptr, 0,
309-
settings_.last_open_dir.empty() ? nullptr : settings_.last_open_dir.c_str());
323+
// Pass null for defaultPath to let OS decide (avoids ShellItem error)
324+
nfdresult_t result = NFD_OpenDialog(&out_path, nullptr, 0, nullptr);
310325

311326
if (result == NFD_OKAY && out_path) {
312327
selected_path = out_path;
328+
// Save the directory for next time
329+
settings_.last_open_dir = std::filesystem::path(out_path).parent_path().string();
313330
NFD_FreePath(out_path);
331+
} else if (result == NFD_CANCEL) {
332+
return;
314333
} else {
334+
fprintf(stderr, "NFD Error: %s\n", NFD_GetError());
315335
return;
316336
}
317337
}
@@ -362,8 +382,8 @@ void EditorApp::open_file(const std::string& path) {
362382
settings_.last_open_dir = std::filesystem::path(selected_path).parent_path().string();
363383
add_recent_file(selected_path);
364384

365-
// Give focus to the editor
366-
ImGui::SetWindowFocus("Editor");
385+
// Set active tab to newly opened file
386+
active_tab_ = tab_idx;
367387
}
368388

369389
bool EditorApp::save_tab(int idx) {
@@ -639,6 +659,7 @@ void EditorApp::toggle_word_wrap() {
639659

640660
void EditorApp::toggle_line_numbers() {
641661
settings_.show_line_numbers = !settings_.show_line_numbers;
662+
// Note: TextEditor always shows line numbers in this version
642663
}
643664

644665
void EditorApp::toggle_spaces() {
@@ -1060,24 +1081,19 @@ void EditorApp::render_editor_with_margins() {
10601081
auto& tab = tabs_[active_tab_];
10611082
TextEditor* editor = tab.editor;
10621083

1063-
// Calculate gutter width: bookmark margin + line number margin + change history margin
1064-
float gutter_width = 0.0f;
1084+
// Show custom gutter only for bookmarks and change history (not line numbers - TextEditor handles that)
10651085
bool has_bookmarks = !tab.bookmarks.empty();
10661086
bool has_changes = !tab.changed_lines.empty();
10671087

1068-
if (has_bookmarks || has_changes || settings_.show_line_numbers) {
1069-
gutter_width = 80.0f; // Combined gutter width
1070-
}
1071-
1072-
if (gutter_width > 0.0f) {
1088+
if (has_bookmarks || has_changes) {
1089+
float gutter_width = 40.0f;
1090+
10731091
ImGui::BeginGroup();
10741092
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
10751093

1076-
// Get cursor position to sync scroll
1077-
auto cursor = editor->GetCursorPosition();
10781094
int total_lines = editor->GetTotalLines();
10791095

1080-
// Render gutter
1096+
// Render gutter for bookmarks and change history
10811097
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.2f, 0.2f, 0.24f, 1.0f));
10821098
if (ImGui::BeginChild("##Gutter", ImVec2(gutter_width, -1), false, ImGuiWindowFlags_NoScrollbar)) {
10831099
for (int line = 0; line < total_lines; line++) {
@@ -1086,20 +1102,16 @@ void EditorApp::render_editor_with_margins() {
10861102
// Bookmark column
10871103
bool is_bookmarked = std::find(tab.bookmarks.begin(), tab.bookmarks.end(), line) != tab.bookmarks.end();
10881104
if (is_bookmarked) {
1089-
ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.0f, 1.0f), "\xE2\x9C\x93"); // Checkmark symbol
1105+
ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.0f, 1.0f), ""); // Checkmark symbol
10901106
} else {
1091-
ImGui::Text(" ");
1107+
ImGui::Text("");
10921108
}
10931109
ImGui::SameLine();
10941110

1095-
// Line number column
1096-
ImGui::TextColored(ImVec4(0.5f, 0.5f, 0.55f, 1.0f), "%d", line + 1);
1097-
ImGui::SameLine();
1098-
10991111
// Change history column (highlight modified lines)
11001112
bool is_changed = std::find(tab.changed_lines.begin(), tab.changed_lines.end(), line) != tab.changed_lines.end();
11011113
if (is_changed) {
1102-
ImGui::TextColored(ImVec4(0.3f, 0.7f, 0.3f, 1.0f), "\xE2\x80\xA2"); // Dot symbol
1114+
ImGui::TextColored(ImVec4(0.3f, 0.7f, 0.3f, 1.0f), ""); // Dot symbol
11031115
}
11041116

11051117
ImGui::PopID();
@@ -1285,11 +1297,49 @@ void EditorApp::render_goto_dialog() {
12851297
}
12861298

12871299
void EditorApp::render_font_dialog() {
1300+
static std::vector<std::string> font_list;
1301+
static bool fonts_loaded = false;
1302+
1303+
if (!fonts_loaded) {
1304+
font_list.clear();
1305+
#ifdef _WIN32
1306+
LOGFONTW lf = {};
1307+
lf.lfCharSet = DEFAULT_CHARSET;
1308+
lf.lfFaceName[0] = '\0';
1309+
lf.lfPitchAndFamily = 0;
1310+
HDC hdc = GetDC(NULL);
1311+
EnumFontFamiliesExW(hdc, &lf, (FONTENUMPROCW)[](const LOGFONTW* lf, const TEXTMETRICW* tm, DWORD fontType, LPARAM lParam) -> int {
1312+
auto* fonts = (std::vector<std::string>*)lParam;
1313+
std::wstring name(lf->lfFaceName);
1314+
if (!name.empty()) {
1315+
std::string narrow(name.begin(), name.end());
1316+
if (std::find(fonts->begin(), fonts->end(), narrow) == fonts->end()) {
1317+
fonts->push_back(narrow);
1318+
}
1319+
}
1320+
return 1;
1321+
}, (LPARAM)&font_list, 0);
1322+
ReleaseDC(NULL, hdc);
1323+
#endif
1324+
fonts_loaded = true;
1325+
}
1326+
12881327
ImGui::OpenPopup("Font Settings");
12891328
ImVec2 center = ImGui::GetMainViewport()->GetCenter();
12901329
ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
12911330

12921331
if (ImGui::BeginPopupModal("Font Settings", &show_font_, ImGuiWindowFlags_AlwaysAutoResize)) {
1332+
ImGui::Text("Font Family:");
1333+
ImGui::SetNextItemWidth(250);
1334+
if (ImGui::BeginCombo("##fontfamily", font_name_temp_.empty() ? "Default" : font_name_temp_.c_str())) {
1335+
for (const auto& font : font_list) {
1336+
if (ImGui::Selectable(font.c_str())) {
1337+
font_name_temp_ = font;
1338+
}
1339+
}
1340+
ImGui::EndCombo();
1341+
}
1342+
12931343
ImGui::Text("Font Size (8-48):");
12941344
ImGui::SetNextItemWidth(100);
12951345
ImGui::InputInt("##fontsize", &font_size_temp_);
@@ -1301,11 +1351,13 @@ void EditorApp::render_font_dialog() {
13011351

13021352
if (ImGui::Button("Apply")) {
13031353
settings_.font_size = font_size_temp_;
1354+
settings_.font_name = font_name_temp_;
13041355
rebuild_fonts();
13051356
}
13061357
ImGui::SameLine();
13071358
if (ImGui::Button("OK")) {
13081359
settings_.font_size = font_size_temp_;
1360+
settings_.font_name = font_name_temp_;
13091361
rebuild_fonts();
13101362
show_font_ = false;
13111363
}

src/editor_app.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,11 @@ struct AppSettings {
5353
// ============================================================================
5454
class EditorApp {
5555
public:
56-
EditorApp();
56+
EditorApp(int argc = 0, char* argv[] = nullptr);
5757
~EditorApp();
5858

5959
int run();
60+
void load_files_from_args(int argc, char* argv[]);
6061

6162
private:
6263
// Lifecycle
@@ -165,6 +166,10 @@ class EditorApp {
165166
int font_size_temp_ = 16;
166167
std::string font_name_temp_ = "";
167168

169+
// Command line args
170+
int argc_ = 0;
171+
char** argv_ = nullptr;
172+
168173
// Spaces submenu state
169174
bool show_spaces_dialog_ = false;
170175
int tab_size_temp_ = 4;

src/main.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@
66
#include "editor_app.h"
77

88
int main(int argc, char* argv[]) {
9-
(void)argc;
10-
(void)argv;
11-
12-
EditorApp app;
9+
EditorApp app(argc, argv);
1310
return app.run();
1411
}

0 commit comments

Comments
 (0)