diff --git a/z.ex.search/build.properties b/z.ex.search/build.properties
index e9863e2..6c480f3 100644
--- a/z.ex.search/build.properties
+++ b/z.ex.search/build.properties
@@ -2,4 +2,5 @@ source.. = src/
output.. = bin/
bin.includes = META-INF/,\
.,\
- plugin.xml
+ plugin.xml,\
+ icons/
diff --git a/z.ex.search/icons/pdf.svg b/z.ex.search/icons/pdf.svg
new file mode 100644
index 0000000..56e57fc
--- /dev/null
+++ b/z.ex.search/icons/pdf.svg
@@ -0,0 +1,3 @@
+
diff --git a/z.ex.search/plugin.xml b/z.ex.search/plugin.xml
index 50b9208..72defc6 100644
--- a/z.ex.search/plugin.xml
+++ b/z.ex.search/plugin.xml
@@ -15,6 +15,11 @@
id="z.ex.search.prevSearchEntry"
name="Previous Search Entry">
+
+
@@ -31,5 +36,35 @@
sequence="ALT+,">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/z.ex.search/src/z/ex/search/BuildRCPScriptHandler.java b/z.ex.search/src/z/ex/search/BuildRCPScriptHandler.java
new file mode 100644
index 0000000..d8699c2
--- /dev/null
+++ b/z.ex.search/src/z/ex/search/BuildRCPScriptHandler.java
@@ -0,0 +1,154 @@
+package z.ex.search;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.swt.program.Program;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.preferences.ScopedPreferenceStore;
+
+public class BuildRCPScriptHandler extends AbstractHandler {
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ // Read paths from preferences
+ IPreferenceStore store = new ScopedPreferenceStore(InstanceScope.INSTANCE, "z.ex.search");
+ String scriptPath = store.getString(PreferenceConstants.SCRIPT_PATH);
+ String pdfOutputPath = store.getString(PreferenceConstants.PDF_OUTPUT_PATH);
+
+ File scriptFile = new File(scriptPath);
+
+ if (!scriptFile.exists()) {
+ showError("Script not found at: " + scriptPath);
+ return null;
+ }
+
+ if (!scriptFile.canExecute()) {
+ showError("Script is not executable: " + scriptPath);
+ return null;
+ }
+
+ // Execute the script using Eclipse Jobs API
+ Job job = new Job("Building RCP") {
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ monitor.beginTask("Executing RCP build script", IProgressMonitor.UNKNOWN);
+
+ try {
+ ProcessBuilder pb = new ProcessBuilder(scriptPath);
+ pb.directory(scriptFile.getParentFile());
+ pb.redirectErrorStream(true);
+
+ Process process = pb.start();
+
+ // Read and collect output
+ StringBuilder output = new StringBuilder();
+ try (BufferedReader reader = new BufferedReader(
+ new InputStreamReader(process.getInputStream()))) {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ output.append(line).append("\n");
+ if (monitor.isCanceled()) {
+ process.destroyForcibly();
+ return Status.CANCEL_STATUS;
+ }
+ }
+ }
+
+ int exitCode = process.waitFor();
+ final boolean success = exitCode == 0;
+
+ if (success) {
+ showSuccessDialog();
+ } else {
+ String message = "Build failed with exit code: " + exitCode +
+ "\n\n" + output.toString();
+ showErrorDialog(message);
+ }
+
+ return Status.OK_STATUS;
+
+ } catch (IOException e) {
+ return new Status(IStatus.ERROR, "z.ex.search",
+ "Error executing script: " + e.getMessage(), e);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ return Status.CANCEL_STATUS;
+ } finally {
+ monitor.done();
+ }
+ }
+ };
+
+ job.setUser(true); // Shows the job in the UI
+ job.schedule();
+
+ return null;
+ }
+
+ private void showError(String message) {
+ Display.getDefault().asyncExec(() -> {
+ MessageDialog.openError(
+ Display.getDefault().getActiveShell(),
+ "Build RCP Script Error",
+ message
+ );
+ });
+ }
+
+ private void showSuccessDialog() {
+ Display.getDefault().asyncExec(() -> {
+ boolean openPdf = MessageDialog.openQuestion(
+ Display.getDefault().getActiveShell(),
+ "Build RCP Script",
+ "RCP build script executed successfully.\n\nDo you want to open the PDF file?"
+ );
+
+ if (openPdf) {
+ openPdfFile();
+ }
+ });
+ }
+
+ private void showErrorDialog(String message) {
+ Display.getDefault().asyncExec(() -> {
+ MessageDialog.openError(
+ Display.getDefault().getActiveShell(),
+ "Build RCP Script Error",
+ message
+ );
+ });
+ }
+
+ private void openPdfFile() {
+ // Read PDF path from preferences
+ IPreferenceStore store = new ScopedPreferenceStore(InstanceScope.INSTANCE, "z.ex.search");
+ String pdfOutputPath = store.getString(PreferenceConstants.PDF_OUTPUT_PATH);
+
+ File pdfFile = new File(pdfOutputPath);
+
+ if (!pdfFile.exists()) {
+ showError("PDF file not found at: " + pdfOutputPath);
+ return;
+ }
+
+ // Use SWT Program to launch the PDF with system default application
+ boolean launched = Program.launch(pdfFile.getAbsolutePath());
+
+ if (!launched) {
+ showError("Failed to open PDF file. No application is associated with PDF files.");
+ }
+ }
+}
diff --git a/z.ex.search/src/z/ex/search/BuildScriptPreferencePage.java b/z.ex.search/src/z/ex/search/BuildScriptPreferencePage.java
new file mode 100644
index 0000000..77f9509
--- /dev/null
+++ b/z.ex.search/src/z/ex/search/BuildScriptPreferencePage.java
@@ -0,0 +1,36 @@
+package z.ex.search;
+
+import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.jface.preference.FieldEditorPreferencePage;
+import org.eclipse.jface.preference.FileFieldEditor;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.ui.preferences.ScopedPreferenceStore;
+
+/**
+ * Preference page for configuring build script paths.
+ */
+public class BuildScriptPreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage {
+
+ public BuildScriptPreferencePage() {
+ super(GRID);
+ }
+
+ @Override
+ public void createFieldEditors() {
+ addField(new FileFieldEditor(PreferenceConstants.SCRIPT_PATH,
+ "&Build Script Path:",
+ getFieldEditorParent()));
+
+ addField(new FileFieldEditor(PreferenceConstants.PDF_OUTPUT_PATH,
+ "&PDF Output Path:",
+ getFieldEditorParent()));
+ }
+
+ @Override
+ public void init(IWorkbench workbench) {
+ setPreferenceStore(new ScopedPreferenceStore(InstanceScope.INSTANCE, "z.ex.search"));
+ setDescription("Configure paths for the RCP build script and PDF output.");
+ }
+
+}
diff --git a/z.ex.search/src/z/ex/search/PreferenceConstants.java b/z.ex.search/src/z/ex/search/PreferenceConstants.java
new file mode 100644
index 0000000..1e49ec5
--- /dev/null
+++ b/z.ex.search/src/z/ex/search/PreferenceConstants.java
@@ -0,0 +1,19 @@
+package z.ex.search;
+
+import java.nio.file.Paths;
+
+/**
+ * Constant definitions for plug-in preferences
+ */
+public class PreferenceConstants {
+
+ public static final String SCRIPT_PATH = "scriptPath";
+ public static final String PDF_OUTPUT_PATH = "pdfOutputPath";
+
+ // Default values
+ public static final String DEFAULT_SCRIPT_PATH = Paths.get(System.getProperty("user.home"),
+ "git", "content", "_scripts", "buildRCPScript.sh").toString();
+ public static final String DEFAULT_PDF_OUTPUT_PATH = Paths.get(System.getProperty("user.home"),
+ "git", "content", "output.pdf").toString();
+
+}
diff --git a/z.ex.search/src/z/ex/search/PreferenceInitializer.java b/z.ex.search/src/z/ex/search/PreferenceInitializer.java
new file mode 100644
index 0000000..a51f9a4
--- /dev/null
+++ b/z.ex.search/src/z/ex/search/PreferenceInitializer.java
@@ -0,0 +1,19 @@
+package z.ex.search;
+
+import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
+import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.ui.preferences.ScopedPreferenceStore;
+
+/**
+ * Initializes default preference values.
+ */
+public class PreferenceInitializer extends AbstractPreferenceInitializer {
+
+ @Override
+ public void initializeDefaultPreferences() {
+ ScopedPreferenceStore store = new ScopedPreferenceStore(InstanceScope.INSTANCE, "z.ex.search");
+ store.setDefault(PreferenceConstants.SCRIPT_PATH, PreferenceConstants.DEFAULT_SCRIPT_PATH);
+ store.setDefault(PreferenceConstants.PDF_OUTPUT_PATH, PreferenceConstants.DEFAULT_PDF_OUTPUT_PATH);
+ }
+
+}