123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- /*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
- #include "Editor.h"
- #include "HackStudio.h"
- #include "HackStudioWidget.h"
- #include "Project.h"
- #include <AK/StringBuilder.h>
- #include <LibConfig/Client.h>
- #include <LibCore/ArgsParser.h>
- #include <LibCore/File.h>
- #include <LibCore/System.h>
- #include <LibGUI/Application.h>
- #include <LibGUI/Menubar.h>
- #include <LibGUI/Notification.h>
- #include <LibGUI/Window.h>
- #include <LibMain/Main.h>
- #include <fcntl.h>
- #include <spawn.h>
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <unistd.h>
- using namespace HackStudio;
- static WeakPtr<HackStudioWidget> s_hack_studio_widget;
- static bool make_is_available();
- static void notify_make_not_available();
- static void update_path_environment_variable();
- static Optional<String> last_opened_project_path();
- ErrorOr<int> serenity_main(Main::Arguments arguments)
- {
- TRY(Core::System::pledge("stdio recvfd sendfd tty rpath cpath wpath proc exec unix fattr thread ptrace"));
- auto app = TRY(GUI::Application::try_create(arguments));
- Config::pledge_domains({ "HackStudio", "Terminal" });
- auto window = GUI::Window::construct();
- window->resize(840, 600);
- window->set_icon(Gfx::Bitmap::try_load_from_file("/res/icons/16x16/app-hack-studio.png").release_value_but_fixme_should_propagate_errors());
- update_path_environment_variable();
- if (!make_is_available()) {
- notify_make_not_available();
- }
- char const* path_argument = nullptr;
- bool mode_coredump = false;
- Core::ArgsParser args_parser;
- args_parser.add_positional_argument(path_argument, "Path to a workspace or a file", "path", Core::ArgsParser::Required::No);
- args_parser.add_option(mode_coredump, "Debug a coredump in HackStudio", "coredump", 'c');
- args_parser.parse(arguments);
- auto argument_absolute_path = Core::File::real_path_for(path_argument);
- auto project_path = Core::File::real_path_for(".");
- if (!mode_coredump) {
- if (!argument_absolute_path.is_null())
- project_path = argument_absolute_path;
- else if (auto path = last_opened_project_path(); path.has_value())
- project_path = path.release_value();
- }
- auto hack_studio_widget = TRY(window->try_set_main_widget<HackStudioWidget>(project_path));
- s_hack_studio_widget = hack_studio_widget;
- window->set_title(String::formatted("{} - Hack Studio", hack_studio_widget->project().name()));
- hack_studio_widget->initialize_menubar(*window);
- window->on_close_request = [&]() -> GUI::Window::CloseRequestDecision {
- hack_studio_widget->locator().close();
- if (hack_studio_widget->warn_unsaved_changes("There are unsaved changes, do you want to save before exiting?") == HackStudioWidget::ContinueDecision::Yes)
- return GUI::Window::CloseRequestDecision::Close;
- return GUI::Window::CloseRequestDecision::StayOpen;
- };
- window->show();
- hack_studio_widget->update_actions();
- if (mode_coredump)
- hack_studio_widget->open_coredump(argument_absolute_path);
- return app->exec();
- }
- static bool make_is_available()
- {
- pid_t pid;
- char const* argv[] = { "make", "--version", nullptr };
- posix_spawn_file_actions_t action;
- posix_spawn_file_actions_init(&action);
- posix_spawn_file_actions_addopen(&action, STDOUT_FILENO, "/dev/null", O_WRONLY, 0);
- if ((errno = posix_spawnp(&pid, "make", &action, nullptr, const_cast<char**>(argv), environ))) {
- perror("posix_spawn");
- return false;
- }
- int wstatus;
- waitpid(pid, &wstatus, 0);
- posix_spawn_file_actions_destroy(&action);
- return WEXITSTATUS(wstatus) == 0;
- }
- static void notify_make_not_available()
- {
- auto notification = GUI::Notification::construct();
- notification->set_icon(Gfx::Bitmap::try_load_from_file("/res/icons/32x32/app-hack-studio.png").release_value_but_fixme_should_propagate_errors());
- notification->set_title("'make' Not Available");
- notification->set_text("You probably want to install the binutils, gcc, and make ports from the root of the Serenity repository");
- notification->show();
- }
- static void update_path_environment_variable()
- {
- StringBuilder path;
- auto const* path_env_ptr = getenv("PATH");
- if (path_env_ptr != NULL)
- path.append({ path_env_ptr, strlen(path_env_ptr) });
- if (path.length())
- path.append(":");
- path.append("/usr/local/sbin:/usr/local/bin:/usr/bin:/bin");
- setenv("PATH", path.to_string().characters(), true);
- }
- static Optional<String> last_opened_project_path()
- {
- auto projects = HackStudioWidget::read_recent_projects();
- if (projects.size() == 0)
- return {};
- if (!Core::File::exists(projects[0]))
- return {};
- return { projects[0] };
- }
- namespace HackStudio {
- GUI::TextEditor& current_editor()
- {
- return s_hack_studio_widget->current_editor();
- }
- void open_file(String const& filename)
- {
- s_hack_studio_widget->open_file(filename);
- }
- void open_file(String const& filename, size_t line, size_t column)
- {
- s_hack_studio_widget->open_file(filename, line, column);
- }
- RefPtr<EditorWrapper> current_editor_wrapper()
- {
- if (!s_hack_studio_widget)
- return nullptr;
- return s_hack_studio_widget->current_editor_wrapper();
- }
- Project& project()
- {
- return s_hack_studio_widget->project();
- }
- String currently_open_file()
- {
- if (!s_hack_studio_widget)
- return {};
- return s_hack_studio_widget->active_file();
- }
- void set_current_editor_wrapper(RefPtr<EditorWrapper> wrapper)
- {
- s_hack_studio_widget->set_current_editor_wrapper(wrapper);
- }
- Locator& locator()
- {
- return s_hack_studio_widget->locator();
- }
- void for_each_open_file(Function<void(ProjectFile const&)> func)
- {
- s_hack_studio_widget->for_each_open_file(move(func));
- }
- bool semantic_syntax_highlighting_is_enabled()
- {
- return s_hack_studio_widget->semantic_syntax_highlighting_is_enabled();
- }
- }
|