Check out "Do you speak JavaScript?" - my latest video course on advanced JavaScript.
Language APIs, Popular Concepts, Design Patterns, Advanced Techniques In the Browser

FlashDevelop scripting: open file by text selection

FlashDevelop is one of the most preferred editors for the flash development. I've been also using it last few years. I found it helpful for writing JavaScript, HTML, CSS and PHP code as well. I just took a big project with over 1000 php files and it is a little bit difficult to open the right file, even by using the Project panel. That's why I decided to invest time in solving this task and found that I can write my own C# script and run it.

The site that I have to work on has a lot of files, but they are distributed in well named folders and basically the name of every class is a combination of folder's path plus the name of the php file. So when I see something like:

$component = new basic_wrapper_component_manager();

I have to open the file /basic/wrapper/component/manager.php. Firstly I was thinking that I will be able to solve the problem by using snippets. My idea was to select the name of the class and call a snippet which will open the file based on the text's selection. Then I realized that I'll need something more, because I have to parse the string. I checked the FlashDevelop's site and found that I can write my own macros. They are powerful tool, but as far as I know it is not possible to manipulate the selected text as I wanted. At the end I managed to solve my problem by writing a script in C# that is called by macros. Here are all the steps that I went through:

Step 1 - creating the macros

Open the macros panel by pressing Ctrl + F10. The panel looks like on the picture below.[1]Click Add button and enter the name of your macros in the Label field. Also set a Shortcut so you can call it fast while you are coding. The real part of the macros has to be written in Entries filed. Because you have to run an external script you have to use the following command:

ExecuteScript|Development;path/to/your/file.cs

My command looks like that:

ExecuteScript|Development;D://WORK//PROJECTS//KRASIMIR TSONEV//CODING//FLASHDEVELOP//Macros//C#//OpenFile.cs

Step 2 - creating a basic script code

The script file has to contain C# code and it has a basic structure like this:

using System;using System.Windows.Forms;using PluginCore;public class FDScript{	private static string file;	private static string projectPath;    public static void Execute() {				MessageBox.Show("Script here");    }	}

Don't worry if you are not familiar with C#. You can still code with a little help from Google. Every script has to contain Execute method which is actually the starting point. I strongly recommend to check this thread in the FlashDevelop's community forum. I followed the instructions there and downloaded Snippet Compiler which is actually pretty good simple C# editor. It also offers code completion and if you add PluginCore.dll you will have completion of the FlashDevelop's things.

Step 3 - creating the actual script

Firstly we should get the current selected text and the current project's directory:

private static string file;private static string projectPath;public static void Execute() {	file = PluginBase.MainForm.CurrentDocument.SciControl.SelText;	projectPath = Path.GetDirectoryName(PluginBase.CurrentProject.ProjectPath);}

When we have this data we can parse the file variable, find the path, the name of the file and open it:

PluginCore.PluginBase.MainForm.OpenEditableDocument(path/file, true);

The main purpose of this script was to use it in this project, but actually I found that I can use it in any other project. I decided to extend it and add additional features. Here is the full code of the script and you can download it from here.

using System;
    using System.Windows.Forms;
    using System.Text;
    using System.Text.RegularExpressions;
    using ScintillaNet;
    using PluginCore;
    using PluginCore.Helpers;
    using System.IO;
    using System.Drawing;
    public class FDScript {
      private static string file;
      private static string projectPath;
      public static void Execute() {
        file = PluginBase.MainForm.CurrentDocument.SciControl.SelText;
        projectPath = Path.GetDirectoryName(PluginBase.CurrentProject.ProjectPath);
        if (file == "") {
          InputBox("File name", "Type a file name:", ref file, "Ok", "Cancel");
        }
        if (file != "") {
          char[] delimiterChars = {
            '_',
            '/'
          };
          foreach(char c in delimiterChars) {
            searchForDelimeters(c);
          }
          // alert(projectPath + "  /  " + file);
          if (!findFile(projectPath, file)) {
            alert("File (" + file + ") not found.");
          }
        }
      }
      public static void searchForDelimeters(char delimeter) {
        string projectPathAddition = "";
        if (file.IndexOf(delimeter) >= 0) {
          string[] pathParts = file.Split(new Char[] {
            delimeter
          });
          int numOfParts = pathParts.Length;
          if (numOfParts > 1) {
            for (int i = 0; i < numOfParts - 1; i++) {
              projectPathAddition += pathParts[i] + "\\\\";
            }
            if (InputBox("Found delimeter '" + delimeter + "'", "Found delimeter '" + delimeter + "'. Search for '" + pathParts[numOfParts - 1] + "' in:", ref projectPathAddition, "Yes", "No") == DialogResult.OK) {
              projectPath += "\\\\" + projectPathAddition;
              file = pathParts[numOfParts - 1];
            }
          }
        }
      }
      public static bool findFile(string dir, string file) {
        bool result = false;
        try {
          foreach(string f in Directory.GetFiles(dir, file + ".?*")) {
            PluginCore.PluginBase.MainForm.OpenEditableDocument(f, true);
            result = true;
          }
          foreach(string d in Directory.GetDirectories(dir)) {
            if (findFile(d, file)) {
              result = true;
            }
          }
        } catch (System.Exception excpt) {
          alert(excpt.Message);
        }
        return result;
      }
      public static void alert(string mess) {
        MessageBox.Show(mess);
      }
      public static DialogResult InputBox(string title, string promptText, ref string value, string labelOk, string labelCancel) {
        Form form = new Form();
        Label label = new Label();
        TextBox textBox = new TextBox();
        Button buttonOk = new Button();
        Button buttonCancel = new Button();
        form.Text = title;
        label.Text = promptText;
        textBox.Text = value;
        buttonOk.Text = labelOk;
        buttonCancel.Text = labelCancel;
        buttonOk.DialogResult = DialogResult.OK;
        buttonCancel.DialogResult = DialogResult.Cancel;
        label.SetBounds(9, 20, 372, 13);
        textBox.SetBounds(12, 36, 372, 20);
        buttonOk.SetBounds(228, 72, 75, 23);
        buttonCancel.SetBounds(309, 72, 75, 23);
        label.AutoSize = true;
        textBox.Anchor = textBox.Anchor | AnchorStyles.Right;
        buttonOk.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
        buttonCancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
        form.ClientSize = new Size(396, 107);
        form.Controls.AddRange(new Control[] {
          label,
          textBox,
          buttonOk,
          buttonCancel
        });
        form.ClientSize = new Size(Math.Max(300, label.Right + 10), form.ClientSize.Height);
        form.FormBorderStyle = FormBorderStyle.FixedDialog;
        form.StartPosition = FormStartPosition.CenterScreen;
        form.MinimizeBox = false;
        form.MaximizeBox = false;
        form.AcceptButton = buttonOk;
        form.CancelButton = buttonCancel;
        DialogResult dialogResult = form.ShowDialog();
        value = textBox.Text;
        return dialogResult;
      }
    }

When you run the script it checks if there is any text selection. If not then open a simple input where you can write in.[2]After that the data is processed and split by using '_' and '/' (searchForDelimeters method). I.e. the script is trying to guess the file's path. Of course you can skip this by clicking the No button.[3]findFile method is used to parse all the project's directories and search for the files based on the file's name.If you want to create your own script I recommend to download the FlashDevelop's code and explore PluginCore's classes, properties and methods.

If you enjoy this post, share it on Twitter, Facebook or LinkedIn.