From e776d64bd14cbc1eb9cd8291cd9c2aa3b8f3cb67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20H=C3=A4hne?= Date: Wed, 31 Mar 2021 15:17:36 +0200 Subject: [PATCH 1/2] Update zinput, known-folders and enable global configuration --- src/known-folders | 2 +- src/main.zig | 24 +++---- src/setup.zig | 177 ++++++++++++++++++++++++---------------------- src/zinput | 2 +- 4 files changed, 104 insertions(+), 101 deletions(-) diff --git a/src/known-folders b/src/known-folders index e1193f9ef..e1794360c 160000 --- a/src/known-folders +++ b/src/known-folders @@ -1 +1 @@ -Subproject commit e1193f9ef5b3aad7a6071e9f5721934fe04a020e +Subproject commit e1794360c0bdd11cc3b7a8b7aaa6cea5a0d61bde diff --git a/src/main.zig b/src/main.zig index 8edb1c6f5..ef56a4340 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1691,6 +1691,7 @@ pub fn main() anyerror!void { // Check arguments. var args_it = std.process.args(); + defer args_it.deinit(); const prog_name = try args_it.next(allocator) orelse unreachable; allocator.free(prog_name); @@ -1703,14 +1704,12 @@ pub fn main() anyerror!void { } else if (std.mem.eql(u8, arg, "config")) { keep_running = false; try setup.wizard(allocator); - args_it.deinit(); return; } else { std.debug.print("Unrecognized argument {s}\n", .{arg}); std.os.exit(1); } } - args_it.deinit(); // Init global vars const reader = std.io.getStdIn().reader(); @@ -1722,22 +1721,21 @@ pub fn main() anyerror!void { defer std.json.parseFree(Config, config, config_parse_options); config_read: { - const res = try known_folders.getPath(allocator, .local_configuration); - - if (res) |local_config_path| { - defer allocator.free(local_config_path); - if (loadConfig(local_config_path)) |conf| { + if (try known_folders.getPath(allocator, .local_configuration)) |path| { + defer allocator.free(path); + if (loadConfig(path)) |conf| { config = conf; break :config_read; } } - - var exe_dir_bytes: [std.fs.MAX_PATH_BYTES]u8 = undefined; - const exe_dir_path = std.fs.selfExeDirPath(&exe_dir_bytes) catch break :config_read; - - if (loadConfig(exe_dir_path)) |conf| { - config = conf; + if (try known_folders.getPath(allocator, .global_configuration)) |path| { + defer allocator.free(path); + if (loadConfig(path)) |conf| { + config = conf; + break :config_read; + } } + logger.info("No config file zls.json found.", .{}); } // Find the zig executable in PATH diff --git a/src/setup.zig b/src/setup.zig index 769490ac9..75edd2d60 100644 --- a/src/setup.zig +++ b/src/setup.zig @@ -2,9 +2,19 @@ const std = @import("std"); const zinput = @import("zinput/src/main.zig"); const known_folders = @import("known-folders"); +fn print(comptime fmt: []const u8, args: anytype) void { + const stdout = std.io.getStdOut().writer(); + stdout.print(fmt, args) catch @panic("Could not write to stdout"); +} + +fn write(text: []const u8) void { + const stdout = std.io.getStdOut().writer(); + stdout.writeAll(text) catch @panic("Could not write to stdout"); +} + pub fn wizard(allocator: *std.mem.Allocator) !void { @setEvalBranchQuota(2500); - std.debug.warn( + write( \\Welcome to the ZLS configuration wizard! \\ * \\ |\ @@ -16,15 +26,52 @@ pub fn wizard(allocator: *std.mem.Allocator) !void { \\ \__-/ / \\ \\ - , .{}); + ); + + var local_path = known_folders.getPath(allocator, .local_configuration) catch null; + var global_path = known_folders.getPath(allocator, .global_configuration) catch null; + defer if (local_path) |d| allocator.free(d); + defer if (global_path) |d| allocator.free(d); + + if (global_path == null and local_path == null) { + write("Could not open a global or local config directory.\n"); + return; + } + var config_path: []const u8 = undefined; + if (try zinput.askBool("Should this configuration be system-wide?")) { + if (global_path) |p| { + config_path = p; + } else { + write("Could not find a global config directory.\n"); + return; + } + } else { + if (local_path) |p| { + config_path = p; + } else { + write("Could not find a local config directory.\n"); + return; + } + } + var dir = std.fs.cwd().openDir(config_path, .{}) catch |err| { + print("Could not open {s}: {}.\n", .{config_path, err}); + return; + }; + defer dir.close(); + var file = dir.createFile("zls.json", .{}) catch |err| { + print("Could not create {s}/zls.json: {}.\n", .{config_path, err}); + return; + }; + defer file.close(); + const out = file.writer(); var zig_exe_path = try findZig(allocator); defer if (zig_exe_path) |p| allocator.free(p); if (zig_exe_path) |path| { - std.debug.print("Found zig executable '{s}' in PATH.\n", .{path}); + print("Found zig executable '{s}' in PATH.\n", .{path}); } else { - std.debug.print("Could not find 'zig' in PATH\n", .{}); + write("Could not find 'zig' in PATH\n"); zig_exe_path = try zinput.askString(allocator, "What is the path to the 'zig' executable you would like to use?", std.fs.MAX_PATH_BYTES); } @@ -43,53 +90,9 @@ pub fn wizard(allocator: *std.mem.Allocator) !void { else => 1024 * 1024, }; - var file: std.fs.File = undefined; - var dir_path: []const u8 = &.{}; - defer allocator.free(dir_path); - - try_config_open: { - if (try known_folders.getPath(allocator, .local_configuration)) |path| local_conf: { - var dir = std.fs.cwd().openDir(path, .{}) catch |err| switch (err) { - error.FileNotFound => { - break :local_conf; - }, - else => |e| { - std.debug.print("Failed to open directory `{s}`. Error: {}\n", .{ path, err }); - return; - }, - }; - defer dir.close(); - file = dir.createFile("zls.json", .{}) catch |err| { - std.debug.print("Failed to create file `{s}/zls.json`. Error: {}\n", .{ path, err }); - return; - }; - dir_path = path; - break :try_config_open; - } - if (try known_folders.getPath(allocator, .executable_dir)) |path| exe_dir: { - var dir = std.fs.cwd().openDir(path, .{}) catch |err| switch (err) { - error.FileNotFound => { - break :exe_dir; - }, - else => |e| { - std.debug.print("Failed to open directory `{s}`. Error: {}\n", .{ path, err }); - return; - }, - }; - defer dir.close(); - file = dir.createFile("zls.json", .{}) catch |err| { - std.debug.print("Failed to create file `{s}/zls.json`. Error: {}\n", .{ path, err }); - return; - }; - dir_path = path; - break :try_config_open; - } - std.debug.print("Could not open the local configuration directory nor the executable directory, aborting.\n", .{}); - return; - } - defer file.close(); - std.debug.print("Writing config to {s}/zls.json ... ", .{dir_path}); - try std.json.stringify(.{ + std.debug.warn("Writing config to {s}/zls.json ... ", .{config_path}); + + const content = std.json.stringify(.{ .zig_exe_path = zig_exe_path, .enable_snippets = snippets, .warn_style = style, @@ -97,84 +100,86 @@ pub fn wizard(allocator: *std.mem.Allocator) !void { .operator_completions = operator_completions, .include_at_in_builtins = include_at_in_builtins, .max_detail_length = max_detail_length, - }, std.json.StringifyOptions{}, file.writer()); - std.debug.print("successful.\n\n\n\n", .{}); + }, std.json.StringifyOptions{}, out); + + write("successful.\n\n\n\n"); + // Keep synced with README.md switch (editor) { .VSCode => { - std.debug.warn( + write( \\To use ZLS in Visual Studio Code, install the 'ZLS for VSCode' extension from \\'https://github.com/zigtools/zls-vscode/releases' or via the extensions menu. \\Then, open VSCode's 'settings.json' file, and add: \\ \\"zigLanguageClient.path": "[command_or_path_to_zls]" - , .{}); + ); }, .Sublime => { - std.debug.warn( + write( \\To use ZLS in Sublime, install the `LSP` package from \\https://github.com/sublimelsp/LSP/releases or via Package Control. \\Then, add the following snippet to LSP's user settings: \\ - \\{{ - \\ "clients": {{ - \\ "zig": {{ + \\{ + \\ "clients": { + \\ "zig": { \\ "command": ["zls"], \\ "enabled": true, \\ "languageId": "zig", \\ "scopes": ["source.zig"], \\ "syntaxes": ["Packages/Zig/Syntaxes/Zig.tmLanguage"] - \\ }} - \\ }} - \\}} - , .{}); + \\ } + \\ } + \\} + ); }, .Kate => { - std.debug.warn( + write( \\To use ZLS in Kate, enable `LSP client` plugin in Kate settings. \\Then, add the following snippet to `LSP client's` user settings: \\(or paste it in `LSP client's` GUI settings) \\ - \\{{ - \\ "servers": {{ - \\ "zig": {{ + \\{ + \\ "servers": { + \\ "zig": { \\ "command": ["zls"], \\ "url": "https://github.com/zigtools/zls", \\ "highlightingModeRegex": "^Zig$" - \\ }} - \\ }} - \\}} - , .{}); + \\ } + \\ } + \\} + ); }, .Neovim, .Vim8 => { - std.debug.warn( + write( \\To use ZLS in Neovim/Vim8, we recommend using CoC engine. \\You can get it from https://github.com/neoclide/coc.nvim. \\Then, simply issue cmd from Neovim/Vim8 `:CocConfig`, and add this to your CoC config: \\ - \\{{ - \\ "languageserver": {{ - \\ "zls" : {{ + \\{ + \\ "languageserver": { + \\ "zls" : { \\ "command": "command_or_path_to_zls", \\ "filetypes": ["zig"] - \\ }} - \\ }} - \\}} - , .{}); + \\ } + \\ } + \\} + ); }, .Emacs => { - std.debug.warn( + write( \\To use ZLS in Emacs, install lsp-mode (https://github.com/emacs-lsp/lsp-mode) from melpa. \\Zig mode (https://github.com/ziglang/zig-mode) is also useful! \\Then, add the following to your emacs config: \\ \\(require 'lsp-mode) \\(setq lsp-zig-zls-executable "") - , .{}); + ); }, .Doom => { - std.debug.warn( + write( \\To use ZLS in Doom Emacs, enable the lsp module \\And install the `zig-mode` (https://github.com/ziglang/zig-mode) \\package by adding `(package! zig-mode)` to your packages.el file. @@ -190,17 +195,17 @@ pub fn wizard(allocator: *std.mem.Allocator) !void { \\ :new-connection (lsp-stdio-connection "") \\ :major-modes '(zig-mode) \\ :server-id 'zls)))) - , .{}); + ); }, .Other => { - std.debug.warn( + write( \\We might not *officially* support your editor, but you can definitely still use ZLS! \\Simply configure your editor for use with language servers and point it to the ZLS executable! - , .{}); + ); }, } - std.debug.warn("\n\nThank you for choosing ZLS!\n", .{}); + write("\n\nThank you for choosing ZLS!\n"); } pub fn findZig(allocator: *std.mem.Allocator) !?[]const u8 { diff --git a/src/zinput b/src/zinput index eae98b3d7..95106b1f7 160000 --- a/src/zinput +++ b/src/zinput @@ -1 +1 @@ -Subproject commit eae98b3d70078c45e3f0d7ec81bb2cf3384187ff +Subproject commit 95106b1f71430f61973f81f7b255f3b319d88828 From fdc37d6da02b76dcf98812217388c13a7f4bffbc Mon Sep 17 00:00:00 2001 From: Tau Date: Sat, 3 Apr 2021 10:15:15 +0200 Subject: [PATCH 2/2] Fix crash on Windows --- src/setup.zig | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/setup.zig b/src/setup.zig index 75edd2d60..e76d734e5 100644 --- a/src/setup.zig +++ b/src/setup.zig @@ -72,7 +72,14 @@ pub fn wizard(allocator: *std.mem.Allocator) !void { print("Found zig executable '{s}' in PATH.\n", .{path}); } else { write("Could not find 'zig' in PATH\n"); - zig_exe_path = try zinput.askString(allocator, "What is the path to the 'zig' executable you would like to use?", std.fs.MAX_PATH_BYTES); + zig_exe_path = try zinput.askString(allocator, + if (std.builtin.os.tag == .windows) + \\What is the path to the 'zig' executable you would like to use? + \\Note that due to a bug in zig (https://github.com/ziglang/zig/issues/6044), + \\your zig directory cannot contain the '/' character. + else + "What is the path to the 'zig' executable you would like to use?", + std.fs.MAX_PATH_BYTES); } const editor = try zinput.askSelectOne("Which code editor do you use?", enum { VSCode, Sublime, Kate, Neovim, Vim8, Emacs, Doom, Other }); @@ -223,6 +230,9 @@ pub fn findZig(allocator: *std.mem.Allocator) !?[]const u8 { var it = std.mem.tokenize(env_path, &[_]u8{std.fs.path.delimiter}); while (it.next()) |path| { + if (std.builtin.os.tag == .windows) { + if (std.mem.indexOfScalar(u8, path, '/')) |s| continue; + } const full_path = try std.fs.path.join(allocator, &[_][]const u8{ path, zig_exe, @@ -230,8 +240,7 @@ pub fn findZig(allocator: *std.mem.Allocator) !?[]const u8 { defer allocator.free(full_path); if (!std.fs.path.isAbsolute(full_path)) continue; - - // Skip folders named zig + const file = std.fs.openFileAbsolute(full_path, .{}) catch continue; defer file.close(); const stat = file.stat() catch continue;