Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
N7 version 24.06.29 released
#3
(06-29-2024, 07:57 PM)johnno56 Wrote: Cool... Great job... One small - cosmetic - issue... When selecting "Help/About" the version displayed it 24.02.16... Not a "deal breaker"... just me being a little "picky"... Moo Ha Ha Ha...


Save this code below as ned.n7, compile it and you will get newer version 24.06.29   Big Grin

Code:
' NED - NaaLaa Editor
' -------------------
' By Marcus 2022 - 2023.

#win32

include "ngui.n7"
include "file.n7"
include "qsort.n7"

' Version.
constant vVersion = "24.06.29"

' Path and files.
visible vPath
visible vDataPath
visible vCompiler = "n7.exe"
visible vDLLs = ["libwinpthread-1.dll", "libportaudio.dll"]

' Themes.
visible vThemes

' Widgets.
visible vEditorTabs, vEditor, vEditorInfoLabel, vOutput, vOutputLabel
visible vFindBar, vReplaceBar, vGotoBar
visible vFindTextEntry
visible vReplaceTextEntry, vReplaceWithTextEntry
visible vGotoTextEntry

visible vEdBoxCloseRequest

' Settings.
'visible vDarkMode = false
visible vTheme = "Default light"
visible vFindCaseSensitive = false
visible vReplaceCaseSensitive = false
visible vEditorFontName = "Courier New"
visible vEdFontSize = 16
visible vHiddenOutput = false
visible vHiddenFunctionList = false

' Command help.
visible vCommandSyntax = unset, vCommandFile = unset

' Only allow one running instance of NED.
if window("NED")
    ' Tell existing window to open the file or just bring the window to front.
    if sizeof(args) > 1  SendWindowMessage("NED", args[1])
    else  SendWindowMessage("NED", "show")
    ' Terminate this instance.
    end
endif

' Save path of executable. If you associate n7 files with ned, the current
' working directory may be wrong when ned is launched.
vPath = GetPath(args[0])
vDataPath = GetPathCombined(GetAppDataDirectory(), "naalaa7")
CreateDirectory(vDataPath)

' Create themes list.
vThemes = []
AddToList(vThemes, [name: "Default light", filename: unset])
AddToList(vThemes, [name: "Default dark", filename: unset])
files = GetFiles(GetPathCombined(GetPathCombined(vPath, "assets"), "themes"))
if files  for i = 0 to sizeof(files) - 1
    AddToList(vThemes, [name: GetFilename(files[i], false), filename: files[i]])
next

' Load command help.
LoadCommandHelp(GetPathCombined(GetPathCombined(vPath, "assets"), "command_help.txt"))

' Create a resizable window.
w = screenw()*2/3
h = screenh()*2/3
set window "NED", w, h, false, 0, min(w, 640), min(h, 480)
set redraw off

' Load settings.
settings = LoadSettings()
documents = settings.docs
for i = 0 to sizeof(vThemes) - 1  if vThemes[i].name = vTheme
    vTheme = vThemes[i]
    break
endif
if i >= sizeof(vThemes)  vTheme = vThemes[0]
if vTheme.filename  LoadTheme(vTheme.filename)
else if vTheme.name = "Default light"  SetDarkMode(false)
else  SetDarkMode(true)
SetTextEditorFont(vEditorFontName, vEdFontSize)

' Create gui.
root = CreateGui()

' Add commands (CTRL+<key>) that we want to process.
AddCommand(KEY_N, NewDocument)
AddCommand(KEY_O, LoadDocument)
AddCommand(KEY_S, SaveOrSaveAll)
AddCommand(KEY_F, ShowFindBar)
AddCommand(KEY_H, ShowReplaceBar)
AddCommand(KEY_G, ShowGotoBar)
AddCommand(KEY_F5, CompileAndRunTarget)
AddCommand(KEY_F7, CompileTarget)
AddCommand(KEY_F6, RunTarget)

' Add other keys that we want to process.
AddFunction(KEY_F1, CommandHelp)
AddFunction(KEY_F3, FindNextOrPrev)
AddFunction(KEY_F5, CompileAndRun)
AddFunction(KEY_F7, Compile)
AddFunction(KEY_F6, Run)

' Add an action for handling window messages from other n7 programs.
SetWindowMessageAction(function(msg)
        if exists(msg)
            existing = unset
            if vEditorTabs.Count() > 0
                for i = 0 to vEditorTabs.Count() - 1
                    if vEditorTabs.GetItem(i).editor.GetFilename() = msg
                        existing = vEditorTabs.GetItem(i)
                        break
                    endif
                next
            endif
            if existing
                vEditorTabs.SelectItem(existing)
            else
                AddNewEditor()
                vEditor.LoadDocument(msg)
                FunctionScan(vEditor)
                SaveSettings()
            endif
        endif
        ShowWindow()
        return true
    endfunc)

' Add some welcome lines to the output window.
vOutput.AddLine("Welcome to the second most primitive IDE thinkable!")
vOutput.AddLine("Compiled with n7 version " + VERSION)

' Any documents from settings?
if sizeof(documents)
    ' Try to load them, last one is the last active file.
    for i = 0 to sizeof(documents) - 2
        if exists(documents[i])
            AddNewEditor()
            vEditor.LoadDocument(documents[i])
            if settings.target = documents[i]
                ToggleTarget()
                settings.target = unset
            endif
            FunctionScan(vEditor)
        endif
    next
    ' Select first tab or last if it exists.
    if vEditorTabs.Count() > 0
        vEditorTabs.SelectIndex(0)
        last = Last(documents)
        if last
            for i = 0 to vEditorTabs.Count() - 1
                if vEditorTabs.GetItem(i).editor.GetFilename() = last
                    vEditorTabs.SelectIndex(i)
                    break
                endif
            next
        endif
    endif
endif

' Any document as parameter?
if sizeof(args) > 1 and exists(args[1])
    ' Check if it exists among the ones already loaded.
    existing = unset
    if vEditorTabs.Count() > 0
        for i = 0 to vEditorTabs.Count() - 1
            if vEditorTabs.GetItem(i).editor.GetFilename() = args[1]
                existing = vEditorTabs.GetItem(i)
                break
            endif
        next
    endif
    ' Set focus to its tab.
    if existing
        vEditorTabs.SelectItem(existing)
    ' Put it in a new tab.
    else
        AddNewEditor()
        vEditor.LoadDocument(args[1])
        FunctionScan(vEditor)
        SaveSettings()
    endif
endif

' No loads?
if vEditorTabs.Count() = 0
    AddNewEditor()
endif


' Enter main loop.
EnterMainLoop(root)


' LoadSettings
' ------------
function LoadSettings()
    f = openfile(GetPathCombined(vDataPath, "ned_config.txt"))
    if not typeof(f)  f = openfile(GetPathCombined(vPath, "ned_config.txt"))
    documents = []
    lastActive = unset
    target = unset
    if typeof(f)
        setting = frln(f)
        while setting
            pair = split(setting, "=")
            if sizeof(pair) = 2
                select pair[0]
                    case "last_doc"  documents[sizeof(documents)] = pair[1]
                    case "last_act"  lastActive = pair[1]
                    case "target_doc"  target = pair[1]
                    case "dark_mode"
                        ' vDarkMode = int(pair[1])
                        if int(pair[1])  vTheme = "Default dark"
                        else  vTheme = "Default light"
                    case "theme"
                        vTheme = pair[1]
                    case "find_case"  vFindCaseSensitive = int(pair[1])
                    case "replace_case"  vReplaceCaseSensitive = int(pair[1])
                    case "ed_font_size"  vEdFontSize = int(pair[1])
                    case "hidden_op"  vHiddenOutput = int(pair[1])
                    case "hidden_fl"  vHiddenFunctionList = int(pair[1])
                endsel
            endif
            setting = frln(f)
        wend
        if sizeof(documents) > 0  documents[sizeof(documents)] = lastActive
        free file f
    endif
    return [docs: documents, target: target]
endfunc

' SaveSettings
' ------------
function SaveSettings()
    f = createfile(GetPathCombined(vDataPath, "ned_config.txt"))
    if typeof(f)
        ' wln file f, "dark_mode=" + vDarkMode
        wln file f, "theme=" + vTheme.name
        wln file f, "find_case=" + vFindCaseSensitive
        wln file f, "replace_case=" + vReplaceCaseSensitive
        wln file f, "ed_font_size=" + vEdFontSize
        wln file f, "hidden_op=" + vHiddenOutput
        wln file f, "hidden_fl=" + vHiddenFunctionList
        if vEditorTabs.Count() > 0
            target = unset
            for i = 0 to vEditorTabs.Count() - 1
                item = vEditorTabs.GetItem(i)
                filename = item.editor.GetFilename()
                if filename  wln file f, "last_doc=" + filename
                tabItem = vEditorTabs.GetTabItem(item)
                if typeof(tabItem.icon)  target = filename
            next
            if vEditor and vEditor.GetFilename()  wln file f, "last_act=" + vEditor.GetFilename()
            if typeof(target) wln file f, "target_doc=" + target
        endif
        free file f
    endif   
endfunc

' CreateGui
' ---------
function CreateGui()
    ' The root of the gui.
    root = VBox(SIZE_EXPAND, SIZE_EXPAND)
    root.background = GetColor(COLOR_BACKGROUND)
    root.SetPadding(0)

    ' Creat a menu bar and add menus to it.
    menuBar = MenuBar()
    ' File menu.
    menu = Menu(FileMenuAction)
    menu.Add("New", "Ctrl+N")
    menu.Add("Load", "Ctrl+O")
    menu.Add("Save", "Ctrl+S")
    menu.Add("Save as", unset)
    menu.Add("Toggle target", unset)
    menu.Add("Save all", "Ctrl+Shift+S")
    menu.Add("Close", unset)
    menu.Add("Close all", unset)
    menu.Add(HDivider(1, 4), unset)
    menu.Add("Exit", unset)
    menuBar.Add("File", menu)
    ' Edit menu.
    menu = Menu(EditMenuAction)
    menu.Add("Undo", "Ctrl+Z")
    menu.Add("Redo", "Ctrl+Y")
    menu.Add(HDivider(1, 4), unset)
    menu.Add("Cut", "Ctrl+X")
    menu.Add("Copy", "Ctrl+C")
    menu.Add("Paste", "Ctrl+V")
    menu.Add("Delete", "Del")
    menu.Add("Select all", "Ctrl+A")
    menu.Add(HDivider(1, 4), unset)
    menu.Add("Find", "Ctrl+F")
    menu.Add("Find next", "F3")
    menu.Add("Find previous", "Shift+F3")
    menu.Add("Replace", "Ctrl+H")
    menu.Add("Goto line", "Ctrl+G")
    menuBar.Add("Edit", menu)
    ' Program menu.
    menu = Menu(ProgramMenuAction)
    menu.Add("Compile and run", "F5")
    menu.Add("Compile", "F7")
    menu.Add("Run", "F6")
    menu.Add(HDivider(1, 4), unset)
    menu.Add("Compile and run target", "Ctrl+F5")
    menu.Add("Compile target", "Ctrl+F7")
    menu.Add("Run target", "Ctrl+F6")
    menuBar.Add("Program", menu)
    ' Help menu.
    menu = Menu(HelpMenuAction)
    menu.Add("Syntax help/example", "F1")
    menu.Add(HDivider(1, 4), unset)
    menu.Add("Increase font size", unset)
    menu.Add("Decrease font size", unset)
    menu.Add(HDivider(1, 4), unset)
    menu.Add("About", unset)
    menuBar.Add("Help", menu)
    ' Add menu
    root.Add(menuBar)
   
    ' Create box for everything but the menu.
    content = VBox(SIZE_EXPAND, SIZE_EXPAND)
    content.SetPadding(0)
    content.SetSpacing(0)

    ' Create a box for the toolbar and settings bar.
    hb = HBox(SIZE_EXPAND, SIZE_AUTO)
    hb.SetValign(ALIGN_CENTER)
    hb.SetPadding(0)

    ' Create toolbar.
    toolbar = HBox(SIZE_EXPAND, SIZE_AUTO)
    toolbar.SetValign(ALIGN_CENTER)
    toolbar.SetPadding(4)
    toolbar.SetSpacing(4)
    ' Add document buttons.
    toolbar.Add(ImageButton(loadimage(GetPathCombined(vPath, "assets/new.png")), function(wdg)
            NewDocument()
        endfunc))
    Last(toolbar.GetChildren()).SetForeground(GetColor(COLOR_PRIMARY_BACKGROUND))
    Last(toolbar.GetChildren()).SetTooltip("Create a new document")
    toolbar.Add(ImageButton(loadimage(GetPathCombined(vPath, "assets/open.png")), function(wdg)
            LoadDocument()
        endfunc))
    Last(toolbar.GetChildren()).SetForeground(GetColor(COLOR_PRIMARY_BACKGROUND))
    Last(toolbar.GetChildren()).SetTooltip("Open a document")
    toolbar.Add(ImageButton(loadimage(GetPathCombined(vPath, "assets/save.png")), function(wdg)
            SaveDocument()
        endfunc))
    Last(toolbar.GetChildren()).SetForeground(GetColor(COLOR_PRIMARY_BACKGROUND))
    Last(toolbar.GetChildren()).SetTooltip("Save document")
    toolbar.Add(ImageButton(loadimage(GetPathCombined(vPath, "assets/close.png")), function(wdg)
            CloseDocument()
        endfunc))
    Last(toolbar.GetChildren()).SetForeground(GetColor(COLOR_PRIMARY_BACKGROUND))
    Last(toolbar.GetChildren()).SetTooltip("Close document")
    toolbar.Add(VDivider(1, 4))
   
    ' Add program buttons.
    toolbar.Add(ImageButton(loadimage(GetPathCombined(vPath, "assets/compile_target.png")), function(wdg)
            CompileTarget()
        endfunc))
    Last(toolbar.GetChildren()).SetForeground(GetColor(COLOR_PRIMARY_BACKGROUND))
    Last(toolbar.GetChildren()).SetTooltip("Compile target file")
    toolbar.Add(ImageButton(loadimage(GetPathCombined(vPath, "assets/run_target.png")), function(wdg)
            CompileAndRunTarget()
        endfunc))
    Last(toolbar.GetChildren()).SetForeground(GetColor(COLOR_PRIMARY_BACKGROUND))
    Last(toolbar.GetChildren()).SetTooltip("Compile and run target file")
    toolbar.Add(ImageButton(loadimage(GetPathCombined(vPath, "assets/compile.png")), function(wdg)
            Compile()
        endfunc))
    Last(toolbar.GetChildren()).SetForeground(GetColor(COLOR_PRIMARY_BACKGROUND))
    Last(toolbar.GetChildren()).SetTooltip("Compile file")
    toolbar.Add(ImageButton(loadimage(GetPathCombined(vPath, "assets/run.png")), function(wdg)
            CompileAndRun()
        endfunc))
    Last(toolbar.GetChildren()).SetForeground(GetColor(COLOR_PRIMARY_BACKGROUND))
    Last(toolbar.GetChildren()).SetTooltip("Compile and run file")

    toolbar.Add(VDivider(1, 4))
    ' Add undo and redo buttons.
    toolbar.Add(ImageButton(loadimage(GetPathCombined(vPath, "assets/undo.png")), function(wdg)
            Undo()
        endfunc))
    Last(toolbar.GetChildren()).SetForeground(GetColor(COLOR_PRIMARY_BACKGROUND))
    Last(toolbar.GetChildren()).SetTooltip("Undo")
    toolbar.Add(ImageButton(loadimage(GetPathCombined(vPath, "assets/redo.png")), function(wdg)
            Redo()
        endfunc))
    Last(toolbar.GetChildren()).SetForeground(GetColor(COLOR_PRIMARY_BACKGROUND))
    Last(toolbar.GetChildren()).SetTooltip("Redo")
    toolbar.Add(VDivider(1, 4))
    ' Add zoom in and out buttons.
    toolbar.Add(ImageButton(loadimage(GetPathCombined(vPath, "assets/zoom_in.png")), function(wdg)
            IncreaseFontSize()
        endfunc))
    Last(toolbar.GetChildren()).SetForeground(GetColor(COLOR_PRIMARY_BACKGROUND))
    Last(toolbar.GetChildren()).SetTooltip("Increase the editor font size")
    toolbar.Add(ImageButton(loadimage(GetPathCombined(vPath, "assets/zoom_out.png")), function(wdg)
            DecreaseFontSize()
        endfunc))
    Last(toolbar.GetChildren()).SetForeground(GetColor(COLOR_PRIMARY_BACKGROUND))
    Last(toolbar.GetChildren()).SetTooltip("Decrease the editor font size")
    ' Add toolbar to box
    hb.Add(toolbar)

    ' Create settings bar.
    settings = HBox(SIZE_EXPAND, SIZE_AUTO)
    settings.SetHalign(ALIGN_RIGHT)
    settings.SetValign(ALIGN_CENTER)
    settings.SetPadding(4)
    settings.SetSpacing(4)
    settings.Add(ImageButton(loadimage(GetPathCombined(vPath, "assets/functions.png")), function(wdg)
            vHiddenFunctionList = not vHiddenFunctionList
            vEditor.box.flist.SetHidden(vHiddenFunctionList)
            vEditor.box.fvbox.SetHidden(vHiddenFunctionList)
            SaveSettings()
        endfunc))
    Last(settings.GetChildren()).SetForeground(GetColor(COLOR_PRIMARY_BACKGROUND))
    Last(settings.GetChildren()).SetTooltip("Show/Hide function list")
    ' Add dark mode checkbox.
    'settings.Add(LabledCheckBox("Night mode", vDarkMode, function(wdg, checked)
    '        vDarkMode = checked
    '        SetDarkMode(vDarkMode)
    '        SaveSettings()
    '    endfunc))
    ' Use a function as tooltip for this one.
    'Last(settings.GetChildren()).GetCheckBox().SetTooltip(function(wdg)
    '        if wdg.IsChecked()  return "Disable night mode"
    '        else  return "Enable night mode"
    '    endfunc)
    settings.Add(Label("Theme", SIZE_AUTO, SIZE_AUTO))
    settings.Add(ComboBox(108, vThemes, function(cb, index)
            item = cb.GetSelectedItem()
            if item
                if item.filename  LoadTheme(item.filename)
                else if item.name = "Default light"  SetDarkMode(false)
                else if item.name = "Default dark"  SetDarkMode(true)
                vTheme = item
                SaveSettings()
            endif
        endfunc))
    Last(settings.GetChildren()).SetDisplayField("name")
    Last(settings.GetChildren()).SelectItem(vTheme)
    ' Add settings to box.
    hb.Add(settings)

    ' Add toolbar and settings bar and a divider.
    content.Add(hb)
    content.Add(HDivider(1, 0))

    ' Hidden find bar.
    vFindBar = VBox(SIZE_EXPAND, SIZE_AUTO)
    vFindBar.SetPadding(0)
    vFindBar.SetHalign(ALIGN_RIGHT)
    hb = HBox(SIZE_AUTO, SIZE_AUTO)
    hb.SetValign(ALIGN_CENTER)
    hb.SetPadding(4)
    hb.SetSpacing(8)
    hb.Add(Label("Find", SIZE_AUTO, SIZE_AUTO))
    vFindTextEntry = TextEntry(100, false)
    vFindTextEntry.SetReturnAction(function(wdg)
            FindNext()
        endfunc)
    vFindTextEntry.SetEscapeAction(function(wdg)
            vFindBar.SetHidden(true)
            SetFocus(vEditor)
        endfunc)
    hb.Add(vFindTextEntry)
    hb.Add(LabledCheckBox("Match case", vFindCaseSensitive, function(wdg, checked)
            vFindCaseSensitive = checked
            SaveSettings()
        endfunc))
    Last(hb.GetChildren()).GetCheckBox().SetTooltip("Match case when searching")
    hb.Add(TextButton("Next", SIZE_AUTO, SIZE_AUTO, function(wdg)
            FindNext()
        endfunc))
    Last(hb.GetChildren()).SetTooltip("Find next")
    hb.Add(TextButton("Prev", SIZE_AUTO, SIZE_AUTO, function(wdg)
            FindPrev()
        endfunc))
    Last(hb.GetChildren()).SetTooltip("Find previous")
    hb.Add(ImageButton(GetImage(IMAGE_CLOSE), function(wdg)
            vFindBar.SetHidden(true)
            SetFocus(vEditor)
        endfunc))
    Last(hb.GetChildren()).SetForeground(GetColor(COLOR_PRIMARY_BACKGROUND))
    Last(hb.GetChildren()).SetPadding(4)
    vFindBar.Add(hb)
    vFindBar.Add(HDivider(1, 0))
    vFindBar.SetHidden(true)
    content.Add(vFindBar)

    ' Hidden find and replace bar.
    vReplaceBar = VBox(SIZE_EXPAND, SIZE_AUTO)
    vReplaceBar.SetPadding(0)
    vReplaceBar.SetHalign(ALIGN_RIGHT)
    hb = HBox(SIZE_AUTO, SIZE_AUTO)
    hb.SetValign(ALIGN_CENTER)
    hb.SetPadding(4)
    hb.SetSpacing(8)
    hb.Add(Label("Replace", SIZE_AUTO, SIZE_AUTO))
    vReplaceTextEntry = TextEntry(100, false)
    vReplaceTextEntry.SetReturnAction(function(wdg)
            ReplaceNext()
        endfunc)
    vReplaceTextEntry.SetTabAction(function(wdg)
            vReplaceWithTextEntry.SelectAll()
            SetFocus(vReplaceWithTextEntry)
        endfunc)
    vReplaceTextEntry.SetEscapeAction(function(wdg)
            vReplaceBar.SetHidden(true)
            SetFocus(vEditor)
        endfunc)           
    hb.Add(vReplaceTextEntry)
    hb.Add(Label("With", SIZE_AUTO, SIZE_AUTO))
    vReplaceWithTextEntry = TextEntry(100, false)
    vReplaceWithTextEntry.SetReturnAction(function(wdg)
            Replace()
        endfunc)
    vReplaceWithTextEntry.SetTabAction(function(wdg)
            vReplaceTextEntry.SelectAll()
            SetFocus(vReplaceTextEntry)
        endfunc)
    vReplaceWithTextEntry.SetEscapeAction(function(wdg)
            vReplaceBar.SetHidden(true)
            SetFocus(vEditor)
        endfunc)
    hb.Add(vReplaceWithTextEntry)
    hb.Add(LabledCheckBox("Match case", vReplaceCaseSensitive, function(wdg, checked)
            vReplaceCaseSensitive = checked
            SaveSettings()
        endfunc))
    Last(hb.GetChildren()).GetCheckBox().SetTooltip("Match case when searching")
    hb.Add(TextButton("Find", SIZE_AUTO, SIZE_AUTO, function(wdg)
            ReplaceNext()
        endfunc))
    Last(hb.GetChildren()).SetTooltip("Find next")
    hb.Add(TextButton("Replace", SIZE_AUTO, SIZE_AUTO, function(wdg)
            Replace()
        endfunc))
    Last(hb.GetChildren()).SetTooltip("Replace current occurrence and find next")
    hb.Add(TextButton("Replace all", SIZE_AUTO, SIZE_AUTO, function(wdg)
            ReplaceAll()
        endfunc))
    Last(hb.GetChildren()).SetTooltip("Replace all occurences")
    hb.Add(ImageButton(GetImage(IMAGE_CLOSE), function(wdg)
            vReplaceBar.SetHidden(true)
            SetFocus(vEditor)
        endfunc))
    Last(hb.GetChildren()).SetForeground(GetColor(COLOR_PRIMARY_BACKGROUND))
    Last(hb.GetChildren()).SetPadding(4)
    vReplaceBar.Add(hb)
    vReplaceBar.Add(HDivider(1, 0))
    vReplaceBar.SetHidden(true)
    content.Add(vReplaceBar)
   
    ' Hidden goto bar.
    vGotoBar = VBox(SIZE_EXPAND, SIZE_AUTO)
    vGotoBar.SetPadding(0)
    vGotoBar.SetHalign(ALIGN_RIGHT)
    hb = HBox(SIZE_AUTO, SIZE_AUTO)
    hb.SetValign(ALIGN_CENTER)
    hb.SetPadding(4)
    hb.SetSpacing(8)
    hb.Add(Label("Line", SIZE_AUTO, SIZE_AUTO))
    vGotoTextEntry = TextEntry(100, true)
    vGotoTextEntry.SetReturnAction(function(wdg)
            Goto()
        endfunc)
    vGotoTextEntry.SetEscapeAction(function(wdg)
            vGotoBar.SetHidden(true)
        endfunc)
    hb.Add(vGotoTextEntry)
    hb.Add(TextButton("Goto", SIZE_AUTO, SIZE_AUTO, function(wdg)
            Goto()
        endfunc))
    Last(hb.GetChildren()).SetTooltip("Goto line")
    hb.Add(ImageButton(GetImage(IMAGE_CLOSE), function(wdg)
            vGotoBar.SetHidden(true)
            SetFocus(vEditor)
        endfunc))
    Last(hb.GetChildren()).SetForeground(GetColor(COLOR_PRIMARY_BACKGROUND))
    Last(hb.GetChildren()).SetPadding(4)
    vGotoBar.Add(hb)
    vGotoBar.Add(HDivider(1, 0))
    vGotoBar.SetHidden(true)
    content.Add(vGotoBar)

    vEditorTabs = TabBox(SIZE_EXPAND, SIZE_EXPAND)
    vEditorTabs.SetAction(EditorTabChanged)
    vEditorTabs.SetCloseRequestAction(EditorTabCloseRequest)
    vEditorTabs.SetCloseAction(EditorTabClosed)
    content.Add(vEditorTabs)

    ' Create a box with a header label for the output text area to the left and
    ' a label with document info to the right.   
    hb = HBox(SIZE_EXPAND, SIZE_AUTO)
    hb.SetPadding(2)
    hb.SetValign(ALIGN_CENTER)
    ' 2k23
    ' Create a box for the output text area and its scrollbar.
    outputBox = HBox(SIZE_EXPAND, 128)
    outputBox.SetHidden(vHiddenOutput)
    if vHiddenOutput  img = GetImage(IMAGE_ARROW_UP)
    else  img = GetImage(IMAGE_ARROW_DOWN)
    hb.Add(ImageButton(img, function(wdg)
        vHiddenOutput = not this.ob.IsHidden()
        this.ob.SetHidden(vHiddenOutput)
        if this.ob.IsHidden()
            this.img = GetImage(IMAGE_ARROW_UP)
            lines = vOutput.GetLines()
            if lines and sizeof(lines)
                vOutputLabel.SetText("Output:  " + lines[sizeof(lines) - 1])
            else
                vOutputLabel.SetText("Output:")
            endif
        else
            this.img = GetImage(IMAGE_ARROW_DOWN)
            vOutputLabel.SetText("Output")
        endif
        this.MarkDirty()
        SaveSettings()
    endfunc))
    Last(hb.GetChildren()).ob = outputBox
    Last(hb.GetChildren()).SetForeground(GetColor(COLOR_PRIMARY_BACKGROUND))
    vOutputLabel = Label("Output", SIZE_EXPAND, SIZE_AUTO)
    hb.Add(vOutputLabel)
    vEditorInfoLabel = Label("", SIZE_EXPAND, SIZE_AUTO)
    vEditorInfoLabel.SetHalign(ALIGN_RIGHT)
    hb.Add(vEditorInfoLabel)
    ' Connect the empty label to the editor.
    'vEditor.SetInfoLabel(Last(hb.GetChildren()))
    ' Add the box.
    content.Add(hb)
    outputBox.SetPadding(2)
    outputBox.SetBorder(1)
    outputBox.SetBorderInside(true)
    ' Create the output text area (a read-only text editor).
    vOutput = TextEditor(SIZE_EXPAND, SIZE_EXPAND)
    vOutput.background = GetColor(COLOR_ED_BACKGROUND)
    vOutput.readOnly = true
    vOutput.maxLines = 64
    vOutput.AddLine_ = vOutput.AddLine
    vOutput.AddLine = function(txt)
        this.AddLine_(txt)
        if vHiddenOutput
            lines = vOutput.GetLines()
            if lines and sizeof(lines)  vOutputLabel.SetText("Output:  " + lines[sizeof(lines) - 1])
        endif
    endfunc
    outputBox.Add(vOutput)
    vsb = VerticalScrollbar(vOutput, SIZE_AUTO, SIZE_EXPAND)
    outputBox.Add(vsb)
    content.Add(outputBox)
   
    ' Add content box to the root.
    root.Add(content)

    return root
endfunc

' AddNewEditor
' ------------
function AddNewEditor()
    ' Create a box for the line number bar, editor and a scrollbar.
    edBox = HBox(SIZE_EXPAND, SIZE_EXPAND)
    edBox.SetPadding(2)
    edBox.SetBorder(1)
    edBox.SetBorderInside(true)
    ' Create and add a line number bar.
    lnBar = LineNumberBar(SIZE_AUTO, SIZE_EXPAND)
    edBox.Add(lnBar)
    ' Create and add the editor.
    vEditor = TextEditor(SIZE_EXPAND, SIZE_EXPAND)
    LoadKeywords(vEditor, GetPathCombined(GetPathCombined(vPath, "assets"), "keywords.txt"))
    vEditor.SetLineNumberBar(lnBar)
    vEditor.SetMaxColumnMarker(100)
    vEditor.SetInfoLabel(vEditorInfoLabel)
    edBox.Add(vEditor)
    edBox.editor = vEditor
    vEditor.box = edBox
    vsb = VerticalScrollbar(vEditor, SIZE_AUTO, SIZE_EXPAND)
    edBox.Add(vsb)
   
    vEditor.helpSyntax = unset

    ' Create and add a function listbox.
    edBox.flist = ListBox([], SIZE_AUTO, SIZE_EXPAND, FunctionSelectAction)
    edBox.flist.ed = vEditor
    edBox.flist.SetInnerPadding(4)
    edBox.flist.SetMinWidth(128)
    edBox.flist.SetBackground(GetColor(COLOR_ED_BACKGROUND))
    vsb = VerticalScrollbar(edBox.flist, SIZE_AUTO, SIZE_EXPAND)
    edBox.fvbox = vsb
    edBox.flist.SetDisplayField("name")
    edBox.flist.SetVolatileTooltip(function(wdg, x, y)
            index = wdg.overIndex ' hack ...
            if index >= 0 and index < sizeof(wdg.GetItems())
                return wdg.GetItems()[index].full
            else
                return unset
            endif
        endfunc)
    edBox.flist.SetHidden(vHiddenFunctionList)
    edBox.fvbox.SetHidden(vHiddenFunctionList)

    edBox.Add(edBox.flist)
    edBox.Add(vsb)

    vEditor.NewDocument()   

    vEditorTabs.Add(vEditor.GetDocumentName(), edBox, true)
    vEditor.SetHeaderLabel(vEditorTabs.GetLabel(edBox))
    vEditorTabs.SelectItem(edBox)
endfunc

' EditotTabChanged
' ----------------
function EditorTabChanged(edBox)
    vEditor = edBox.editor
    vEditor.box.flist.SetHidden(vHiddenFunctionList)
    vEditor.box.fvbox.SetHidden(vHiddenFunctionList)   
    SetFocus(vEditor)
endfunc

' EditorTabCloseRequest
' ---------------------
function EditorTabCloseRequest(edBox)
    if edBox.editor.Touched()
        ' Warn about changes. Should add a button "Save and close", could look at vEdBoxCloseRequest
        ' after saving, close and unset.
        msg = chr(34) + edBox.editor.GetDocumentName() + chr(34) + " has unsaved changes." + chr(10)
        msg = msg + "Do you still want to close the tab?"
        vEdBoxCloseRequest = edBox
        ShowMessageBox("Warning", msg, ["Yes", "No"], function(popup, buttonIndex)
                if buttonIndex = 0
                    if vEditorTabs.Count() = 1  AddNewEditor()
                    vEditorTabs.Close(vEdBoxCloseRequest)
                endif
                vEdBoxCloseRequest = unset
            endfunc)
        return false
    else
        ' Add a new empty document if this is the last tab.
        if vEditorTabs.Count() = 1  AddNewEditor()
        return true
    endif
endfunc

' EditorTabClosed
' ---------------
function EditorTabClosed(edBox)
    SaveSettings()
endfunc

' FileMenuAction
' --------------
function FileMenuAction(menu, selectedIndex)
    select selectedIndex
        case 0  NewDocument()
        case 1  LoadDocument()
        case 2  SaveDocument()
        case 3  SaveDocumentAs()
        case 4  ToggleTarget()
        case 5  SaveAllDocuments()
        case 6  CloseDocument()
        case 7  CloseAllDocuments()
        case 8  Exit()
    endsel
endfunc

' EditMenuAction
' --------------
function EditMenuAction(menu, selectedIndex)
    select selectedIndex
        case 0  Undo()
        case 1  Redo()
        case 2  Cut()
        case 3  Copy()
        case 4  Paste()
        case 5  Delete()
        case 6  SelectAll()
        case 7  ShowFindBar()
        case 8  FindNext()
        case 9  FindPrev()
        case 10  ShowReplaceBar()
        case 11  ShowGotoBar()
    endsel
endfunc

' ProgramMenuAction
' -----------------
function ProgramMenuAction(menu, selectedIndex)
    select selectedIndex
        case 0  CompileAndRun()
        case 1  Compile()
        case 2  Run()
        case 3  CompileAndRunTarget()
        case 4  CompileTarget()
        case 5  RunTarget()
    endsel
endfunc

' HelpMenuAction
' --------------
function HelpMenuAction(menu, selectedIndex)
    select selectedIndex
        case 0  CommandHelp()
        case 1  IncreaseFontSize()
        case 2  DecreaseFontSize()
        case 3  About()
    endsel
endfunc

' NewDocument
' -----------
function NewDocument()
    AddNewEditor()
endfunc

' LoadDocument
' ------------
function LoadDocument()
    filename = openfiledialog("n7")
    if filename and exists(filename)
        ' Loaded document goes into a new editor unless the active editor is an empty new document.
        if vEditor.Touched() or vEditor.GetFilename()  AddNewEditor()
        vEditor.LoadDocument(filename)
        SaveSettings()
        FunctionScan(vEditor)
    endif
endfunc

' SaveDocument
' --------------
function SaveDocument()
    if vEditor.GetFilename()
        if vEditor.SaveDocument()
            vOutput.AddLine("Saved " + chr(34) + vEditor.GetFilename() + chr(34))
            SaveSettings()
            FunctionScan(vEditor)
            return true
        else
            vOutput.AddLine("Could not save " + chr(34) + vEditor.GetFilename() + chr(34))
            return false
        endif
    else
        return SaveDocumentAs()
    endif
endfunc

' SaveDocumentAs
' --------------
function SaveDocumentAs()
    filename = savefiledialog("n7")
    if filename
        extFound = false
        for i = len(filename) - 1 to 0
            c = mid(filename, i)
            if c = "\" or c = "/"  break
            if c = "."
                extFound = true
                break
            endif
        next
        if not extFound  filename = filename + ".n7"

        vEditor.SetFilename(filename)
        return SaveDocument()
    else
        return false
    endif
endfunc

' ToggleTarget
' ------------
function ToggleTarget()
    edBox = vEditorTabs.GetCurrentItem()
    current = vEditorTabs.GetTabItem(edBox)
    if current.icon
        current.SetIcon(unset, unset)
        SaveSettings()
    else
        if len(edBox.editor.GetFilename())
            foreach item in vEditorTabs.items.children  item.SetIcon(unset, unset)
            current.SetIcon(GetImage(IMAGE_ARROW_RIGHT), GetColor(COLOR_PRIMARY_BACKGROUND))
            SaveSettings()
        else
            txt =       "You can't target a document" + chr(10)
            txt = txt + "that has never been saved."
            ShowMessageBox("Sorry", txt, "Close", unset)       
        endif
    endif
endfunc

' SaveAllDocuments
' ----------------
' Well, doesn't save documents that hasn't previously been saved.
function SaveAllDocuments()
    if vEditorTabs.Count() > 0
        for i = 0 to vEditorTabs.Count() - 1
            ed = vEditorTabs.GetItem(i).editor
            if ed.GetFilename()  ed.SaveDocument()
        next
    endif
endfunc

' SaveOrSaveAll
' -------------
' Comand key callback, have to check KEY_SHIFT ourselves to distinguish between ctrl+s and
' ctrl+shift+s. Probably should extend AddCommand to handle the shift key.
function SaveOrSaveAll()
    if keydown(KEY_SHIFT)  SaveAllDocuments()
    else  SaveDocument()
endfunc

' CloseDocument
' -------------
' Close current document.
function CloseDocument()
    if vEditor.Touched()
        msg = chr(34) + vEditor.GetDocumentName() + chr(34) + " has unsaved changes." + chr(10)
        msg = msg + "Do you still want to close the tab?"
        ShowMessageBox("Warning", msg, ["Yes", "No"], function(popup, buttonIndex)
                if buttonIndex = 0
                    vEditorTabs.Close(vEditor.box)
                    if vEditorTabs.Count() = 0  AddNewEditor()
                endif
            endfunc)
    else
        vEditorTabs.Close(vEditor.box)
        if vEditorTabs.Count() = 0  AddNewEditor()
    endif
endfunc

' UnsavedDocuments
' ----------------
function UnsavedDocuments()
    unsaved = []
    for i = 0 to vEditorTabs.Count() - 1
        if vEditorTabs.GetItem(i).editor.Touched()
            unsaved[sizeof(unsaved)] = vEditorTabs.GetItem(i).editor.GetDocumentName()
        endif
    next
    return unsaved
endfunc

' CloseAllDocuments
' -----------------
' Close all dodumcnets
function CloseAllDocuments()
    unsaved = UnsavedDocuments()
    if sizeof(unsaved)
        txt = "The following documents have unsaved changes:" + chr(10)
        for i = 0 to sizeof(unsaved) - 1  txt = txt + unsaved[i] + chr(10)
        txt = txt + "Do you still want to close all documents?"
        ShowMessageBox("Warning", txt, ["Yes", "No"], function(popup, buttonIndex)
                if buttonIndex = 0
                    vEditorTabs.CloseAll(false)
                    AddNewEditor()
                    SaveSettings()
                endif
            endfunc)
        return
    else
        vEditorTabs.CloseAll(false)
        AddNewEditor()
        SaveSettings()
    endif
endfunc

' Exit
' ----
' Sadly only called when using the menu to exit. Not quite sure how to lett n7 programs handle the
' window's close button yet ...
function Exit()
    if vEditorTabs.Count() > 0
        unsaved = UnsavedDocuments()
        if sizeof(unsaved)
            txt = "The following documents have unsaved changes:" + chr(10)
            for i = 0 to sizeof(unsaved) - 1  txt = txt + unsaved[i] + chr(10)
            txt = txt + "Do you still want to exit?"
            ShowMessageBox("Warning", txt, ["Yes", "No"], function(popup, buttonIndex)
                    if buttonIndex = 0
                        ExitMainLoop()
                    endif
                endfunc)
            return
        endif
    endif
    ExitMainLoop()
endfunc

' Undo
' ----
function Undo()
    vEditor.Undo()
endfunc

' Redo
' ----
function Redo()
    vEditor.Redo()
endfunc

' Cut
' ---
function Cut()
    vEditor.Cut()
endfunc

' Copy
' ----
function Copy()
    vEditor.Copy()
endfunc

' Paste
' -----
function Paste()
    vEditor.Paste()
endfunc

' Delete
' ------
function Delete()
    vEditor.Delete()
endfunc

' SelectAll
' ---------
function SelectAll()
    vEditor.SelectAll()
endfunc

' ShowFindBar
' -----------
function ShowFindBar()
    if vFindBar.IsHidden()  vFindBar.SetHidden(false)
    if not vReplaceBar.IsHidden()  vReplaceBar.SetHidden(true)
    if not vGotoBar.IsHidden()  vGotoBar.SetHidden(true)
    vFindTextEntry.SelectAll()
    SetFocus(vFindTextEntry)
endfunc

' FindNext
' --------
function FindNext()
    txt = vFindTextEntry.GetText()
    if txt
        if not vEditor.FindNext(txt, not vFindCaseSensitive)
            vOutput.AddLine("Could not find " + chr(34) + txt + chr(34))
        endif
    endif
endfunc

' FindPrev
' --------
function FindPrev()
    txt = vFindTextEntry.GetText()
    if len(txt)
        if not vEditor.FindPrev(txt, not vFindCaseSensitive)
            vOutput.AddLine("Could not find " + chr(34) + txt + chr(34))
        endif
    endif
endfunc

' FindNextOrPrev
' --------------
' Command key callback.
function FindNextOrPrev()
    if keydown(KEY_SHIFT)  FindPrev()
    else  FindNext()
endfunc

' ShowReplaceBar
' --------------
function ShowReplaceBar()
    if vReplaceBar.IsHidden()  vReplaceBar.SetHidden(false)
    if not vFindBar.IsHidden()  vFindBar.SetHidden(true)
    if not vGotoBar.IsHidden()  vGotoBar.SetHidden(true)
    SetFocus(vReplaceTextEntry)
    vReplaceTextEntry.SelectAll()
endfunc

' Replace
' -------
function Replace()
    txt = vReplaceTextEntry.GetText()
    if len(txt) > 0
        ' Replace if current selection matches search.
        if (vReplaceCaseSensitive and vEditor.GetSelection() = txt) or
                (vReplaceCaseSensitive = false and lower(vEditor.GetSelection()) = lower(txt))
            vEditor.PasteString(vReplaceWithTextEntry.txt)
        endif
        ' Find next.
        if not vEditor.FindNext(txt, not vReplaceCaseSensitive)
            vOutput.AddLine("Could not find " + chr(34) + txt + chr(34))             
        endif
    endif
endfunc

' ReplaceNext
' -----------
function ReplaceNext()
    txt = vReplaceTextEntry.GetText()
    if len(txt) > 0
        if not vEditor.FindNext(txt, not vReplaceCaseSensitive)
            vOutput.AddLine("Could not find " + chr(34) + txt + chr(34))             
        endif
    endif
endfunc

' ReplaceAll
' ----------
function ReplaceAll()
    txt = vReplaceTextEntry.GetText()
    rep = vReplaceWithTextEntry.GetText()
    if len(txt) > 0
        count = vEditor.ReplaceAll(txt, rep, not vReplaceCaseSensitive)
        if count
            vOutput.AddLine("Replaced " + count + " occurrence(s) of " + chr(34) + txt + chr(34) +
                    " with " + chr(34) + rep + chr(34))
        else
            vOutput.AddLine("Could not find " + chr(34) + txt + chr(34))
        endif
    endif
endfunc

' ShowGotoBar
' -----------
function ShowGotoBar()
    if vGotoBar.IsHidden()  vGotoBar.SetHidden(false)
    if not vFindBar.IsHidden()  vFindBar.SetHidden(true)
    if not vReplaceBar.IsHidden()  vReplaceBar.SetHidden(true)
    vGotoTextEntry.SelectAll()
    SetFocus(vGotoTextEntry)
endfunc

' Goto
' ----
function Goto()
    ln = int(vGotoTextEntry.GetText())
    vGotoBar.SetHidden(true)
    if not vEditor.Goto(ln) vOutput.AddLine(ln + " is an invalid line number")
    SetFocus(vEditor)
endfunc

' CompileAndRun
' -------------
function CompileAndRun()
    if Compile()  Run()
endfunc

' Compile
' -------
function Compile()
    if SaveDocument()
        fn = vEditor.GetFilename()
        vOutput.AddLine("Compiling " + chr(34) + fn + chr(34))
        cmd = chr(34) + chr(34) + GetPathCombined(vPath, vCompiler) + chr(34) + " " +
                chr(34) + fn + chr(34) + chr(34)
        result = system(cmd)
        lines = split(result, chr(10))
        vOutput.AddLine(result)
        ' Success?
        if sizeof(lines) = 3 and left(lines[2], 12) = "n7b: success"
            ' Copy DLL files.
            if sizeof(vDLLs)
                for i = len(fn) - 1 to 0  if mid(fn, i) = "\" or mid(fn, i) = "/"  break
                path = left(fn, i + 1)
                for i = 0 to sizeof(vDLLs) - 1
                    ' Uhm, what if the version has changed of a dll?
                    'if not exists(path + vDLLs[i])
                        system "copy /Y " + chr(34) + GetPathCombined(vPath, vDLLs[i]) + chr(34) + " " +
                                chr(34) + path + chr(34)
                    'endif
                next
            endif
            return true
        endif
    endif
    return false
endfunc

' Run
' ---
function Run()
    fn = vEditor.GetFilename()
    if len(fn) > 0
        for i = len(fn) - 1 to 0  if mid(fn, i) = "."  break
        fn = left(fn, i) + ".exe"
        if exists(fn)
            vOutput.AddLine("Executing " + chr(34) + fn + chr(34))
            ' Old, nedgui, version
            'system("start " + chr(34) + chr(34) + " " + chr(34) + fn + chr(34))
            cmd = "cd /D " + chr(34) + GetPath(fn) + chr(34) +
                    " && start " + chr(34) + chr(34) + " " + chr(34) + fn + chr(34)
            'vOutput.AddLine(cmd)
            system(cmd)
        else
            vOutput.AddLine("Could not find " + chr(34) + fn + chr(34))
        endif
    endif
    return false
endfunc

' hack.
function FindTargetEditor()
    foreach item in vEditorTabs.items.children
        if typeof(item.icon)  return item.content
    next
    return unset
endfunc

' CompileAndRunTarget
' -------------------
function CompileAndRunTarget()
    target = FindTargetEditor()
    if typeof(target)
        current = vEditorTabs.GetCurrentItem()
        vEditorTabs.SelectItem(target)
        CompileAndRun()
        vEditorTabs.SelectItem(current)
    else
        vOutput.AddLine("No target found for compiling and running")
    endif
endfunc

' CompileTarget
' --------------
function CompileTarget()
    target = FindTargetEditor()
    if typeof(target)
        current = vEditorTabs.GetCurrentItem()
        vEditorTabs.SelectItem(target)
        Compile()
        vEditorTabs.SelectItem(current)
    else
        vOutput.AddLine("No target found for compiling")
    endif
endfunc

' RunTarget
' ---------
function RunTarget()
    target = FindTargetEditor()
    if typeof(target)
        current = vEditorTabs.GetCurrentItem()
        vEditorTabs.SelectItem(target)
        Run()
        vEditorTabs.SelectItem(current)
    else
        vOutput.AddLine("No target found for running")
    endif
endfunc


' IncreaseFontSize
' ----------------
function IncreaseFontSize()
    vEdFontSize = min(vEdFontSize + 2, 24)
    SetTextEditorFont(vEditorFontName, vEdFontSize)
    SaveSettings()
endfunc

' DecreaseFontSize
' ----------------
function DecreaseFontSize()
    vEdFontSize = max(vEdFontSize - 2, 14)
    SetTextEditorFont(vEditorFontName, vEdFontSize)
    SaveSettings()
endfunc

' About
' -----
function About()
    txt = "Version " + vVersion + ", by Marcus" + chr(10)
    txt = txt + "Compiled with n7 version " + VERSION + chr(10) + " " + chr(10)
    txt = txt + "This program is public domain (CC0), so feel" + chr(10)
    txt = txt + "free to do whatever you want with it."
    ShowMessageBox("NED - NaaLaa Editor", txt, "Close", unset)
endfunc

' CommandHelp
' -----------
function CommandHelp()
    hasHelp = vEditor.GetHelp()
   
    vEditor.ShowHelp(unset)

    ln = vEditor.GetCurrentLine()
    le = len(ln)
    startPos = vEditor.GetCaretX()
    leftPos = startPos
    c = asc(mid(ln, leftPos))
    while leftPos >= 0 and (c = 32 or IsAlpha(c))
        leftPos = leftPos - 1
        c = asc(mid(ln, leftPos))
    wend
    leftPos = leftPos + 1
    rightPos = startPos
    c = asc(mid(ln, rightPos))
    while rightPos < le and (c = 32 or IsAlpha(c))
        rightPos = rightPos + 1
        c = asc(mid(ln, rightPos))
    wend   
    s = mid(ln, leftPos, rightPos - leftPos)
    if not s  return

    words = split(s, " ")
    if not sizeof(words)  return

    pos = startPos
    while pos >= 0 and asc(mid(ln, pos)) = 32  pos = pos - 1
    currentWord = GetWordAt(ln, pos)
       
    ' Check user functions.
    if currentWord
        foreach uf in vEditor.box.flist.GetItems()
            if uf.name = currentWord
                vEditor.ShowHelp(uf.full)
                return
            endif
        next
    endif

    if not vCommandSyntax
        vOutput.AddLine("No command help loaded")
        return
    endif   
           
    for index = 0 to sizeof(words) - 1  if words[index] = currentWord  break
    while index >= 0 and not vEditor.IsKeyword(words[index])  index = index - 1
    if index < 0
        vOutput.AddLine("No syntax help found")
        return
    endif
   
    mainKeyword = words[index]
   
    minKeywordIndex = index
    maxKeywordIndex = index
   
    while minKeywordIndex > 0 and vEditor.IsKeyword(words[minKeywordIndex - 1])
        minKeywordIndex = minKeywordIndex - 1
    wend
    while maxKeywordIndex < sizeof(words) - 1 and vEditor.IsKeyword(words[maxKeywordIndex + 1])
        maxKeywordIndex = maxKeywordIndex + 1
    wend

    maxWords = 0
    syntax = unset
    link = unset
    ' I have covid, and I'm tired ...
    for i = minKeywordIndex to maxKeywordIndex
        for j = i to maxKeywordIndex
            if i <= index and j >= index
                s = words[i]
                if j > i  for k = i + 1 to j  s = s + " " + words[k]
                if key(vCommandSyntax, s) and j + 1 - i > maxWords
                    maxWords = j + 1 - i
                    syntax = vCommandSyntax[s]
                    if key(vCommandFile, s)
                        link = vCommandFile[s]
                    else ' Shouldn't happen unless I mess up the file ...
                        link = unset
                    endif
                endif
            endif
        next
    next
    if syntax
        if hasHelp and syntax = vEditor.helpSyntax
            fn = GetPathCombined(GetPathCombined(GetPathCombined(vPath, "examples"), "help"), link)
            if exists(fn)
                vEditor.helpSyntax = unset
                AddNewEditor()
                vEditor.LoadDocument(fn)
                SaveSettings()
                FunctionScan(vEditor)
                return
            else
                vOutput.AddLine("Could not load example " + chr(34) + fn + chr(34))
            endif
        else
            if link
                vEditor.ShowHelp(syntax + "   (Press F1 again to load an example)")
                vEditor.helpSyntax = syntax
            else
                vEditor.ShowHelp(syntax)
                vEditor.helpSyntax = unset
            endif
        endif
    else
        vOutput.AddLine("No syntax help found")
    endif
endfunc

function GetWordAt(ln, pos)
    le = len(ln)
    if pos < 0 or pos >= le or not IsAlpha(asc(mid(ln, pos))) return unset

    if pos = 0
        s = 0
    else
        s = pos
        while s > 0 and IsAlpha(asc(mid(ln, s - 1)))  s = s - 1
    endif
    e = pos + 1
    while s < le and IsAlpha(asc(mid(ln, e)))  e = e + 1
    return mid(ln, s, e - s)
endfunc


function IsAlpha(c)
    return c >= 65 and c <= 90 or c >= 97 and c <= 122
endfunc

function IsLowerAlpha(c)
    return c >= 97 and c <= 122
endfunc

function FunctionSelectAction(wdg, index)
    if index < 0  return

    'wdg.SelectIndex(-1)

    ed = wdg.ed
    wanted = wdg.GetItems()[index]
    lines = ed.GetLines()
    lineNumber = 0
    ln = lines[lineNumber]
    foundAtLine = -1
    do
        skipLine = true
        if instr(ln, "function ") >= 0
            ' Remove all string constants.
            lft = instr(ln, chr(34))
            while lft >= 0
                rgt = instr(ln, chr(34), lft + 1)
                if rgt >= 0
                    ln = left(ln, lft) + right(ln, rgt + 1)
                    lft = instr(ln, chr(34))
                else
                    break
                endif
            wend
            ' Remove comment.
            cmt = instr(ln, "'")
            if cmt >= 0  ln = left(ln, cmt)
            ' Look for function again.
            fnc = instr(ln, "function ")
            if fnc >= 0
                fnc = fnc + 9
                ' Look for (
                lpt = instr(ln, "(", fnc)
                if lpt >= 0
                    fncName = replace(mid(ln, fnc, lpt - fnc), " ", "")
                    ' Ignore unnamed functions.
                    if len(fncName) and fncName = wanted.name
                        foundAtLine = lineNumber
                    else
                        ln = right(ln, lpt + 1)
                        skipLine = false
                    endif
                endif
            endif
        endif
        if skipLine
            lineNumber = lineNumber + 1
            if lineNumber < sizeof(lines)
                ln = lines[lineNumber]
            else
                ln = unset
            endif
        endif
    until foundAtLine >= 0 or ln = unset

    if not (foundAtLine >= 0 and vEditor.Goto(foundAtLine + 1))
        vOutput.AddLine("Could not locate function " + wanted.name)
    endif
endfunc

function FunctionScan(ed)
    lines = ed.GetLines()
    lineNumber = 0
    ln = lines[lineNumber]
    listBox = ed.box.flist;
    flist = listBox.GetItems()

    selIndex = listBox.GetSelectedIndex()
    if selIndex >= 0
        if selIndex < sizeof(listBox.GetItems())
            selName = listBox.GetItems()[selIndex].name
        endif
    else
        selName = unset
    endif

    clear flist
    do
        skipLine = true
        if instr(ln, "function ") >= 0
            ' Remove all string constants.
            lft = instr(ln, chr(34))
            while lft >= 0
                rgt = instr(ln, chr(34), lft + 1)
                if rgt >= 0
                    ln = left(ln, lft) + right(ln, rgt + 1)
                    lft = instr(ln, chr(34))
                else
                    break
                endif
            wend
            ' Remove comment.
            cmt = instr(ln, "'")
            if cmt >= 0  ln = left(ln, cmt)
            ' Look for function again.
            fnc = instr(ln, "function ")
            if fnc >= 0
                fnc = fnc + 9
                ' Look for (
                lpt = instr(ln, "(", fnc)
                if lpt >= 0
                    fncName = replace(mid(ln, fnc, lpt - fnc), " ", "")
                    ' Ignore unnamed functions.
                    if len(fncName)
                        ' Now let's see ...
                        ln = right(ln, lpt + 1)
                        foul = false
                        prms = ""
                        do
                            ' Remove comment.
                            cmt = instr(ln, "'")
                            if cmt >= 0  ln = left(ln, cmt)
                            cm = instr(ln, ",")
                            while cm >= 0
                                pname = replace(left(ln, cm), " ", "")
                                ln = right(ln, cm + 1)
                                if len(pname)
                                    for i = 0 to len(pname) - 1
                                        if not IsAlphaOrDigit(asc(mid(pname, i)))
                                            foul = true
                                            break
                                        endif
                                    next
                                    if foul  break
                                    prms = prms + pname + " "
                                else
                                    foul = true
                                    break
                                endif
                                cm = instr(ln, ",")
                            wend
                            if foul  break
                            rpt = instr(ln, ")")
                            if rpt >= 0
                                pname = replace(left(ln, rpt), " ", "")
                                ln = right(ln, rpt + 1)
                                if len(pname)
                                    for i = 0 to len(pname) - 1
                                        if not IsAlphaOrDigit(asc(mid(pname, i)))
                                            foul = true
                                            break
                                        endif
                                    next
                                    if foul  break
                                    prms = prms + pname + " "
                                endif
                                skipLine = false
                                break
                            else
                                lineNumber = lineNumber + 1
                                if lineNumber < sizeof(lines)
                                    ln = lines[lineNumber]
                                else
                                    foul = true
                                    ln = unset
                                    break
                                endif
                            endif
                        loop
                        if not foul
                            if len(prms) prms = left(prms, len(prms) - 1)
                            flist[sizeof(flist)] = [
                                    name: fncName,
                                    full: fncName + "(" + replace(prms, " ", ", ") + ")"]
                        endif
                    endif
                endif   
            endif
        endif

        if skipLine
            lineNumber = lineNumber + 1
            if lineNumber < sizeof(lines)
                ln = lines[lineNumber]
            else
                ln = unset
            endif
        endif
    until ln = unset

    listBox.ItemsChanged()
    if selName
        foreach k, i in listBox.GetItems()
            if i.name = selName
                listBox.SelectIndex(k)
                break
            endif
        next
    endif

endfunc

function LoadCommandHelp(filename)
    f = openfile(filename)
    if typeof(f)
        vCommandSyntax = []
        vCommandFile = []
        cmd = fread(f)
        while cmd
            syntax = fread(f)
            fn = fread(f)
            if syntax and filename
                vCommandSyntax[cmd] = syntax
                vCommandFile[cmd] = fn
               
                fn = GetPathCombined(GetPathCombined(GetPathCombined(vPath, "examples"), "help"), fn)
            endif
            cmd = fread(f)
        wend
        free file f
    endif
endfunc

' LoadKeywords
' ------------
' Load keywords from file and add them to an editor.
function LoadKeywords(ed, filename)
    f = openfile(filename)
    if typeof(f)
        ed.ClearKeywords()
        kw = fread(f)
        type = 0
        while typeof(kw)
            ' There are two predefined keyword types with different colors (COLOR_SH_KEYWORD and
            ' COLOR_SH_CONSTANT)
            if kw = "keywords:"  type = 0
            elseif kw = "constants:"  type = 1
            else if len(kw)  ed.AddKeyword(kw, type)
            kw = fread(f)
        wend
        free file f
    endif
endfunc
Reply


Messages In This Thread
N7 version 24.06.29 released - by Marcus - 06-29-2024, 03:31 PM
RE: N7 version 24.06.29 released - by johnno56 - 06-29-2024, 07:57 PM
RE: N7 version 24.06.29 released - by 1micha.elok - 07-02-2024, 11:02 AM
RE: N7 version 24.06.29 released - by Marcus - 07-02-2024, 07:49 PM

Forum Jump:


Users browsing this thread: 2 Guest(s)