diff --git a/src/PanelCode.js b/src/PanelCode.js index fb95b424a..0ea3f5eb4 100644 --- a/src/PanelCode.js +++ b/src/PanelCode.js @@ -5,6 +5,7 @@ import { makeDropdownFlat, settings as global_settings } from "./util.js"; import { setupRustProject } from "./langs/rust/rust.js"; import { setupTypeScriptProject } from "./langs/typescript/typescript.js"; import { setupJavascriptProject } from "./langs/javascript/javascript.js"; +import { setupValaProject } from "./langs/vala/vala.js"; export default function PanelCode({ builder, @@ -62,6 +63,10 @@ export default function PanelCode({ ); } + if (panel.language.toLowerCase() === "vala") { + setupValaProject(file).catch(console.error); + } + if (panel.language.toLowerCase() === "rust") { setupRustProject(file).catch(console.error); } diff --git a/src/cli/main.js b/src/cli/main.js index 77ca0f791..1ea39519e 100644 --- a/src/cli/main.js +++ b/src/cli/main.js @@ -352,16 +352,30 @@ async function ci({ filenames }) { const languageId = "vala"; let version = 0; - const file_api = Gio.File.new_for_path(pkg.pkgdatadir).get_child( - "workbench.vala", - ); - file_api.copy( + const current_dir = Gio.File.new_for_path(GLib.get_current_dir()); + + const template_dir = GLib.getenv("FLATPAK_ID") + ? Gio.File.new_for_path( + `/app/share/${GLib.getenv("FLATPAK_ID")}/langs/vala/template`, + ) + : current_dir.resolve_relative_path("src/langs/vala/template"); + + const api_file = template_dir.get_child("workbench.vala"); + api_file.copy( demo_dir.get_child("workbench.vala"), Gio.FileCopyFlags.OVERWRITE, null, null, ); + const meson_file = template_dir.get_child("meson.build"); + meson_file.copy( + demo_dir.get_child("meson.build"), + Gio.FileCopyFlags.OVERWRITE, + null, + null, + ); + const [contents] = await file_vala.load_contents_async(null); const text = new TextDecoder().decode(contents); diff --git a/src/langs/vala/Compiler.js b/src/langs/vala/Compiler.js index 6590493f8..c951b6ab3 100644 --- a/src/langs/vala/Compiler.js +++ b/src/langs/vala/Compiler.js @@ -1,49 +1,79 @@ import Gio from "gi://Gio"; import dbus_previewer from "../../Previewer/DBusPreviewer.js"; -import { decode } from "../../util.js"; +import { createTmpDir, copy } from "../../util.js"; +import { setupValaProject } from "./vala.js"; + +let ready_to_build = false; +const session_build_dir = await createTmpDir("vala"); export default function ValaCompiler({ session }) { const { file } = session; - const module_file = file.get_child("libworkbenchcode.so"); - const file_vala = file.get_child("main.vala"); + const meson_builddir = "builddir"; + const module_file = session_build_dir + .get_child(meson_builddir) + .get_child("libworkbenchcode.so"); async function compile() { - let args; + if (!ready_to_build) { + try { + await setupValaProject(session_build_dir); + ready_to_build = true; + } catch (err) { + console.error(err); + return false; + } + } - try { - const [contents] = await file_vala.load_contents_async(null); - const code = decode(contents); - args = getValaCompilerArguments(code); - } catch (error) { - console.debug(error); - return; + await copy( + "main.vala", + file, + session_build_dir, + Gio.FileCopyFlags.OVERWRITE | Gio.FileCopyFlags.ALL_METADATA, + ); + + // TODO: Do not run setup if the build directory is already + // configured + const meson_launcher = new Gio.SubprocessLauncher(); + meson_launcher.set_cwd(session_build_dir.get_path()); + const meson_setup = meson_launcher.spawnv([ + "meson", + "setup", + meson_builddir, + ]); + + await meson_setup.wait_async(null); + const setup_result = meson_setup.get_successful(); + if (!setup_result) { + return false; } - const valac_launcher = new Gio.SubprocessLauncher(); - valac_launcher.set_cwd(file.get_path()); - const valac = valac_launcher.spawnv([ - "valac", - file_vala.get_path(), - "--hide-internal", - "-X", - "-shared", - "-X", - "-fpic", - "--library", - "workbench", - "-o", - module_file.get_path(), - "--vapi", - "/dev/null", - ...args, + const meson_clean = meson_launcher.spawnv([ + "meson", + "compile", + "--clean", + "-C", + meson_builddir, ]); - await valac.wait_async(null); + await meson_clean.wait_async(null); + if (!meson_clean.get_successful()) { + return false; + } + + const meson_compile = meson_launcher.spawnv([ + "meson", + "compile", + "-C", + meson_builddir, + ]); + + await meson_compile.wait_async(null); + const compile_result = meson_compile.get_successful(); - const result = valac.get_successful(); - valac_launcher.close(); - return result; + meson_launcher.close(); + + return compile_result; } async function run() { @@ -60,11 +90,3 @@ export default function ValaCompiler({ session }) { return { compile, run }; } - -// Takes a string starting with the line -// #!/usr/bin/env -S vala workbench.vala --pkg gtk4 --pkg libadwaita-1 -// and return ["--pkg", "gtk4", "--pkg", "libadwaita-1"] -// FIXME: consider using https://docs.gtk.org/glib/struct.OptionContext.html instead -function getValaCompilerArguments(text) { - return text.split("\n")[0]?.split("-S vala ")[1]?.split(" ") || []; -} diff --git a/src/langs/vala/meson.build b/src/langs/vala/meson.build new file mode 100644 index 000000000..52d566beb --- /dev/null +++ b/src/langs/vala/meson.build @@ -0,0 +1,2 @@ +install_data(['template/meson.build', 'template/workbench.vala'], + install_dir : join_paths(pkgdatadir, 'langs/vala/template')) \ No newline at end of file diff --git a/src/langs/vala/template/meson.build b/src/langs/vala/template/meson.build new file mode 100644 index 000000000..54e19be49 --- /dev/null +++ b/src/langs/vala/template/meson.build @@ -0,0 +1,39 @@ +project('demo', ['c', 'vala'], + version: '0.1', + meson_version: '>= 0.59.0', + default_options: [ 'warning_level=2', 'werror=false', ], +) + +i18n = import('i18n') +gnome = import('gnome') + +source_files = [ + 'main.vala', + 'workbench.vala' +] + +cc = meson.get_compiler('c') +m_dep = cc.find_library('m', required : false) + +add_project_arguments( + '-shared', + '-fpic', + language: 'c' +) + +dependencies = [ + m_dep, + dependency('libadwaita-1'), + dependency('shumate-1.0'), + dependency('libportal-gtk4'), + dependency('libsoup-3.0'), + dependency('webkitgtk-6.0'), + dependency('gstreamer-1.0'), + dependency('gtksourceview-5'), + dependency('json-glib-1.0'), +] + +library('workbenchcode', source_files, + dependencies: dependencies, + install: true, +) \ No newline at end of file diff --git a/src/langs/vala/workbench.vala b/src/langs/vala/template/workbench.vala similarity index 100% rename from src/langs/vala/workbench.vala rename to src/langs/vala/template/workbench.vala diff --git a/src/langs/vala/vala.js b/src/langs/vala/vala.js index 319a98dc7..002d25885 100644 --- a/src/langs/vala/vala.js +++ b/src/langs/vala/vala.js @@ -2,22 +2,16 @@ import Gio from "gi://Gio"; import { isValaAvailable } from "../../Extensions/Extensions.js"; import { createLSPClient } from "../../common.js"; -import { getLanguage } from "../../util.js"; +import { getLanguage, copy } from "../../util.js"; export function setup({ document }) { if (!isValaAvailable()) return; const { file, buffer, code_view } = document; - const api_file = Gio.File.new_for_path(pkg.pkgdatadir).get_child( - "workbench.vala", - ); - api_file.copy( - file.get_parent().get_child("workbench.vala"), - Gio.FileCopyFlags.OVERWRITE, - null, - null, - ); + // VLS needs the project to be already setup once it starts, + // otherwise it won't pick it up later. + setupValaProject(file.get_parent()).catch(console.error); const lspc = createLSPClient({ lang: getLanguage("vala"), @@ -44,3 +38,24 @@ export function setup({ document }) { return lspc; } + +const vala_template_dir = Gio.File.new_for_path( + pkg.pkgdatadir, +).resolve_relative_path("langs/vala/template"); + +export async function setupValaProject(destination) { + return Promise.all([ + copy( + "meson.build", + vala_template_dir, + destination, + Gio.FileCopyFlags.OVERWRITE, + ), + copy( + "workbench.vala", + vala_template_dir, + destination, + Gio.FileCopyFlags.OVERWRITE, + ), + ]); +} diff --git a/src/meson.build b/src/meson.build index a07187bd5..9d8db22f9 100644 --- a/src/meson.build +++ b/src/meson.build @@ -18,6 +18,7 @@ meson.add_install_script('../build-aux/library.js', pkgdatadir) subdir('langs/javascript') subdir('langs/rust/template') subdir('langs/typescript') +subdir('langs/vala') configure_file( input: 'bin.js', @@ -46,7 +47,6 @@ configure_file( install_dir: get_option('bindir') ) -install_data('langs/vala/workbench.vala', install_dir: pkgdatadir) install_data('langs/javascript/biome.json', install_dir: pkgdatadir) install_data('project-readme.md', install_dir: pkgdatadir) subdir('libworkbench') diff --git a/src/util.js b/src/util.js index 958307cb2..86e3aff72 100644 --- a/src/util.js +++ b/src/util.js @@ -211,3 +211,25 @@ export async function copy(filename, source_dir, dest_dir, flags) { return dest_file; } + +const tmp_dirs = {}; + +export async function createTmpDir(filename) { + if (filename in tmp_dirs) { + return tmp_dirs[filename]; + } + + const tmp_dir = Gio.File.new_for_path( + GLib.build_filenamev([GLib.get_tmp_dir(), filename]), + ); + + try { + tmp_dir.make_directory(null); + tmp_dirs[filename] = tmp_dir; + } catch (err) { + console.error(err); + return null; + } + + return tmp_dir; +}