diff --git a/source/ide/config/cfg_global.bas b/source/ide/config/cfg_global.bas index 538aa5f3c..6c6b99f2d 100644 --- a/source/ide/config/cfg_global.bas +++ b/source/ide/config/cfg_global.bas @@ -30,6 +30,8 @@ DIM SHARED StripDebugSymbols AS LONG DIM SHARED OptimizeCppProgram AS LONG DIM SHARED GenerateLicenseFile AS LONG DIM SHARED UseGuiDialogs AS _UNSIGNED LONG +DIM SHARED DefaultTerminal AS STRING +DIM SHARED LoggingEnabled AS _UNSIGNED LONG '===== Define and check settings location ===================================== ConfigFolder$ = "settings" 'relative config location inside the qb64pe main folder diff --git a/source/ide/config/cfg_methods.bas b/source/ide/config/cfg_methods.bas index ba8ab4be4..ed5d1adb9 100644 --- a/source/ide/config/cfg_methods.bas +++ b/source/ide/config/cfg_methods.bas @@ -263,6 +263,14 @@ SUB ReadInitialConfig UseGuiDialogs = ReadWriteBooleanSettingValue%(generalSettingsSection$, "UseGuiDialogs", -1) + DefaultTerminal = ReadWriteStringSettingValue$(generalSettingsSection$, "DefaultTerminal", "") + If DefaultTerminal = "" AND OS$ = "LNX" AND MacOSX = 0 Then + DefaultTerminal = findWorkingTerminal$ + WriteConfigSetting generalSettingsSection$, "DefaultTerminal", DefaultTerminal + End If + + LoggingEnabled = ReadWriteBooleanSettingValue%(generalSettingsSection$, "LoggingEnabled", 0) + '--- Mouse settings result = ReadConfigSetting(mouseSettingsSection$, "SwapMouseButton", value$) IF UCASE$(value$) = "TRUE" OR VAL(value$) = -1 THEN diff --git a/source/ide/ide_global.bas b/source/ide/ide_global.bas index fb6bc75b9..1045e17ae 100644 --- a/source/ide/ide_global.bas +++ b/source/ide/ide_global.bas @@ -228,6 +228,7 @@ DIM SHARED FileMenuExportAs AS INTEGER, FileMenuExportAsSubMenuID AS INTEGER DIM SHARED ViewMenuCompilerWarnings AS INTEGER DIM SHARED RunMenuID AS INTEGER, RunMenuSaveExeWithSource AS INTEGER, brackethighlight AS INTEGER DIM SHARED GenerateLicenseEnableMenu AS INTEGER +DIM SHARED LoggingEnableMenu AS INTEGER DIM SHARED OptionsMenuGuiDialogs AS INTEGER DIM SHARED DebugMenuID AS INTEGER, DebugMenuCallStack AS INTEGER, DebugMenuWatchListToConsole AS INTEGER DIM SHARED DebugMenuAutoAddCommand AS INTEGER diff --git a/source/ide/ide_methods.bas b/source/ide/ide_methods.bas index b66c3074c..87c7ad543 100644 --- a/source/ide/ide_methods.bas +++ b/source/ide/ide_methods.bas @@ -308,6 +308,13 @@ FUNCTION ide2 (ignore) menuDesc$(m, i - 1) = "Sets string returned by COMMAND$ function" menu$(m, i) = "-": i = i + 1 + LoggingEnableMenu = i + menu$(m, i) = "Display #Logging Output": i = i + 1 + menuDesc$(m, i - 1) = "Turns on logging output and displays it in a console window" + IF LoggingEnabled THEN + menu$(RunMenuID, LoggingEnableMenu) = CHR$(7) + menu$(RunMenuID, LoggingEnableMenu) + END IF + RunMenuSaveExeWithSource = i menu$(m, i) = "Output EXE to Source #Folder": i = i + 1 menuDesc$(m, i - 1) = "Toggles compiling program to QB64-PE's folder or to source folder" @@ -320,6 +327,10 @@ FUNCTION ide2 (ignore) IF GenerateLicenseFile THEN menu$(RunMenuID, GenerateLicenseEnableMenu) = CHR$(7) + menu$(RunMenuID, GenerateLicenseEnableMenu) END IF + IF os$ = "LNX" AND MacOSX = 0 THEN + menu$(m, i) = "Change #Terminal": i = i + 1 + menuDesc$(m, i - 1) = "Configure the terminal used for $CONSOLE and logging output" + END IF menu$(m, i) = "-": i = i + 1 IF os$ = "LNX" THEN @@ -5177,6 +5188,21 @@ FUNCTION ide2 (ignore) + IF MID$(menu$(m, s), 1) = "Display #Logging Output" OR MID$(menu$(m, s), 2) = "Display #Logging Output" THEN + PCOPY 2, 0 + LoggingEnabled = NOT LoggingEnabled + WriteConfigSetting generalSettingsSection$, "LoggingEnabled", BoolToTFString$(LoggingEnabled) + + IF LoggingEnabled THEN + menu$(RunMenuID, LoggingEnableMenu) = CHR$(7) + "Display #Logging Output" + ELSE + menu$(RunMenuID, LoggingEnableMenu) = "Display #Logging Output" + END IF + + PCOPY 3, 0: SCREEN , , 3, 0 + GOTO ideloop + END IF + IF RIGHT$(menu$(m, s), 28) = "Output EXE to Source #Folder" THEN PCOPY 2, 0 SaveExeWithSource = NOT SaveExeWithSource @@ -5207,6 +5233,17 @@ FUNCTION ide2 (ignore) GOTO ideloop END IF + IF menu$(m, s) = "Change #Terminal" THEN + PCOPY 2, 0 + + ideTerminalBox + + 'retval is ignored + PCOPY 3, 0: SCREEN , , 3, 0 + GOTO ideloop + END IF + + IF RIGHT$(menu$(m, s), 29) = "#Output Watch List to Console" THEN PCOPY 2, 0 WatchListToConsole = NOT WatchListToConsole @@ -15785,6 +15822,150 @@ FUNCTION ideCompilerSettingsBox LOOP END FUNCTION +SUB ideTerminalBox + + '-------- generic dialog box header -------- + PCOPY 0, 2 + PCOPY 0, 1 + SCREEN , , 1, 0 + focus = 1 + DIM p AS idedbptype + DIM o(1 TO 100) AS idedbotype + DIM sep AS STRING * 1 + sep = CHR$(0) + '-------- end of generic dialog box header -------- + + '-------- init -------- + + i = 0 + + idepar p, 60, 7, "Default Terminal" + + i = i + 1 + PrevFocus = 1 + o(i).typ = 1 + o(i).y = 2 + o(i).nam = idenewtxt("Terminal Command") + o(i).txt = idenewtxt(DefaultTerminal) + o(i).sx1 = 0 + o(i).v1 = LEN(DefaultTerminal) + + i = i + 1 + o(i).typ = 3 + o(i).y = 7 + o(i).txt = idenewtxt("#OK" + sep + "#Cancel") + o(i).dft = 1 + '-------- end of init -------- + + '-------- generic init -------- + FOR i = 1 TO 100: o(i).par = p: NEXT 'set parent info of objects + '-------- end of generic init -------- + + DO 'main loop + + + '-------- generic display dialog box & objects -------- + idedrawpar p + f = 1: cx = 0: cy = 0 + FOR i = 1 TO 100 + IF o(i).typ THEN + + 'prepare object + o(i).foc = focus - f 'focus offset + o(i).cx = 0: o(i).cy = 0 + idedrawobj o(i), f 'display object + IF o(i).cx THEN cx = o(i).cx: cy = o(i).cy + END IF + NEXT i + lastfocus = f - 1 + '-------- end of generic display dialog box & objects -------- + + '-------- custom display changes -------- + LOCATE p.y + 4, p.x + 2 + PRINT CHR$(34) + "$$" + CHR$(34) + " is replaced with the executable"; + LOCATE p.y + 5, p.x + 2 + PRINT CHR$(34) + "$@" + CHR$(34) + " is replaced with the COMMAND$ string"; + '-------- end of custom display changes -------- + + 'update visual page and cursor position + PCOPY 1, 0 + IF cx THEN SCREEN , , 0, 0: LOCATE cy, cx, 1: SCREEN , , 1, 0 + + '-------- read input -------- + change = 0 + DO + GetInput + IF mWHEEL THEN change = 1 + IF KB THEN change = 1 + IF mCLICK THEN mousedown = 1: change = 1 + IF mRELEASE THEN mouseup = 1: change = 1 + IF mB THEN change = 1 + alt = KALT: IF alt <> oldalt THEN change = 1 + oldalt = alt + _LIMIT 100 + LOOP UNTIL change + IF alt AND NOT KCTRL THEN idehl = 1 ELSE idehl = 0 + 'convert "alt+letter" scancode to letter's ASCII character + altletter$ = "" + IF alt AND NOT KCTRL THEN + IF LEN(K$) = 1 THEN + k = ASC(UCASE$(K$)) + IF k >= 65 AND k <= 90 THEN altletter$ = CHR$(k) + END IF + END IF + SCREEN , , 0, 0: LOCATE , , 0: SCREEN , , 1, 0 + '-------- end of read input -------- + + '-------- generic input response -------- + info = 0 + IF K$ = "" THEN K$ = CHR$(255) + IF KSHIFT = 0 AND K$ = CHR$(9) THEN focus = focus + 1 + IF (KSHIFT AND K$ = CHR$(9)) OR (INSTR(_OS$, "MAC") AND K$ = CHR$(25)) THEN focus = focus - 1: K$ = "" + IF focus < 1 THEN focus = lastfocus + IF focus > lastfocus THEN focus = 1 + f = 1 + FOR i = 1 TO 100 + t = o(i).typ + IF t THEN + focusoffset = focus - f + ideobjupdate o(i), focus, f, focusoffset, K$, altletter$, mB, mousedown, mouseup, mX, mY, info, mWHEEL + END IF + NEXT + '-------- end of generic input response -------- + + 'specific post controls + IF focus <> PrevFocus THEN + 'Always start with TextBox values selected upon getting focus + PrevFocus = focus + IF focus = 1 THEN + o(focus).v1 = LEN(idetxt(o(focus).txt)) + IF o(focus).v1 > 0 THEN o(focus).issel = -1 + o(focus).sx1 = 0 + END IF + END IF + + IF K$ = CHR$(27) OR (focus = 3 AND info <> 0) THEN + ClearMouse + EXIT SUB + END IF + + IF K$ = CHR$(13) OR (focus = 2 AND info <> 0) THEN + DefaultTerminal = idetxt(o(1).txt) + + WriteConfigSetting generalSettingsSection$, "DefaultTerminal", DefaultTerminal + + ClearMouse + _KEYCLEAR + EXIT SUB + END IF + 'end of custom controls + + mousedown = 0 + mouseup = 0 + LOOP + +END SUB + FUNCTION idemessagebox (titlestr$, messagestr$, buttons$) '-------- generic dialog box header -------- diff --git a/source/qb64pe.bas b/source/qb64pe.bas index 1ed0459de..9b24f85cc 100644 --- a/source/qb64pe.bas +++ b/source/qb64pe.bas @@ -37,7 +37,6 @@ DEFLNG A-Z '-------- Optional IDE Component (1/2) -------- '$INCLUDE:'ide\ide_global.bas' - DIM SHARED NoExeSaved AS INTEGER DIM SHARED vWatchErrorCall$, vWatchNewVariable$, vWatchVariableExclusions$ @@ -898,8 +897,69 @@ IF C = 9 THEN 'run 'execute program + IF LoggingEnabled THEN + ENVIRON "QB64PE_LOG_HANDLERS=console" + ENVIRON "QB64PE_LOG_SCOPES=qb64,libqb,libqb-image,libqb-audio" + ELSE + ENVIRON "QB64PE_LOG_HANDLERS=" + ENVIRON "QB64PE_LOG_SCOPES=" + END IF + + ExecuteLine$ = "" + + IF MacOSX THEN + IF path.exe$ = "" THEN path.exe$ = "./" + + IF LEFT$(lastBinaryGenerated$, LEN(path.exe$)) = path.exe$ THEN + ExecuteName$ = _FULLPATH$(lastBinaryGenerated$) + ELSE + ExecuteName$ = _FULLPATH$(path.exe$ + lastBinaryGenerated$) + END IF + + IF path.exe$ = "./" THEN path.exe$ = "" + + IF GetRCStateVar(ConsoleOn) OR LoggingEnabled THEN + IF LoggingEnabled THEN handler$ = "console" ELSE handler$ = "" + + generateMacOSLogScript ExecuteName$, handler$, "qb64,libqb,libqb-image,libqb-audio", ModifyCOMMAND$, tmpdir$ + "log.command" + + ' Spawning a program in a terminal is done via `open`. + ' We have to use a separate script to be able to set environment variables for the program + ExecuteLine$ = "open -b com.apple.terminal " + _CHR_QUOTE + tmpdir$ + "log.command" + _CHR_QUOTE + ELSE + ExecuteLine$ = ExecuteName$ + END IF + ELSEIF os$ = "WIN" THEN + IF GetRCStateVar(ConsoleOn) OR LoggingEnabled THEN + PrePend$ = "cmd /c" + ELSE + PrePend$ = "" + END IF + + ExecuteLine$ = PrePend$ + QuotedFilename$(CHR$(34) + lastBinaryGenerated$ + CHR$(34)) + ModifyCOMMAND$ + ELSEIF os$ = "LNX" THEN + IF path.exe$ = "" THEN path.exe$ = "./" + + IF GetRCStateVar(ConsoleOn) OR LoggingEnabled THEN + ExecuteLine$ = DefaultTerminal + + IF LEFT$(lastBinaryGenerated$, LEN(path.exe$)) = path.exe$ THEN + ExecuteLine$ = StrReplace$(ExecuteLine$, "$$", QuotedFilename$(lastBinaryGenerated$)) + ELSE + ExecuteLine$ = StrReplace$(ExecuteLine$, "$$", QuotedFilename$(path.exe$ + lastBinaryGenerated$)) + END IF + ExecuteLine$ = StrReplace$(ExecuteLine$, "$@", ModifyCOMMAND$) + ELSE + IF LEFT$(lastBinaryGenerated$, LEN(path.exe$)) = path.exe$ THEN + ExecuteLine$ = QuotedFilename$(lastBinaryGenerated$) + ModifyCOMMAND$ + ELSE + ExecuteLine$ = QuotedFilename$(path.exe$ + lastBinaryGenerated$) + ModifyCOMMAND$ + END IF + END IF + IF path.exe$ = "./" THEN path.exe$ = "" + END IF IF iderunmode = 1 THEN IF NoExeSaved THEN @@ -907,17 +967,16 @@ IF C = 9 THEN 'run 'saving an EXE file to the disk. 'We start off by first running the EXE, and then we delete it from the drive. 'making it a temporary file when all is said and done. + SHELL ExecuteLine$ + IF os$ = "WIN" THEN - SHELL QuotedFilename$(CHR$(34) + lastBinaryGenerated$ + CHR$(34)) + ModifyCOMMAND$ 'run the newly created program SHELL _HIDE _DONTWAIT "del " + QuotedFilename$(CHR$(34) + lastBinaryGenerated$ + CHR$(34)) 'kill it END IF IF path.exe$ = "" THEN path.exe$ = "./" IF os$ = "LNX" THEN IF LEFT$(lastBinaryGenerated$, LEN(path.exe$)) = path.exe$ THEN - SHELL QuotedFilename$(lastBinaryGenerated$) + ModifyCOMMAND$ KILL lastBinaryGenerated$ ELSE - SHELL QuotedFilename$(path.exe$ + lastBinaryGenerated$) + ModifyCOMMAND$ KILL path.exe$ + lastBinaryGenerated$ END IF END IF @@ -927,29 +986,10 @@ IF C = 9 THEN 'run GOTO sendcommand END IF - - - IF os$ = "WIN" THEN SHELL _DONTWAIT QuotedFilename$(CHR$(34) + lastBinaryGenerated$ + CHR$(34)) + ModifyCOMMAND$ - IF path.exe$ = "" THEN path.exe$ = "./" - IF os$ = "LNX" THEN - IF LEFT$(lastBinaryGenerated$, LEN(path.exe$)) = path.exe$ THEN - SHELL _DONTWAIT QuotedFilename$(lastBinaryGenerated$) + ModifyCOMMAND$ - ELSE - SHELL _DONTWAIT QuotedFilename$(path.exe$ + lastBinaryGenerated$) + ModifyCOMMAND$ - END IF - END IF - IF path.exe$ = "./" THEN path.exe$ = "" + SHELL _DONTWAIT ExecuteLine$ ELSE - IF os$ = "WIN" THEN SHELL QuotedFilename$(CHR$(34) + lastBinaryGenerated$ + CHR$(34)) + ModifyCOMMAND$ - IF path.exe$ = "" THEN path.exe$ = "./" - IF os$ = "LNX" THEN - IF LEFT$(lastBinaryGenerated$, LEN(path.exe$)) = path.exe$ THEN - SHELL QuotedFilename$(lastBinaryGenerated$) + ModifyCOMMAND$ - ELSE - SHELL QuotedFilename$(path.exe$ + lastBinaryGenerated$) + ModifyCOMMAND$ - END IF - END IF - IF path.exe$ = "./" THEN path.exe$ = "" + SHELL ExecuteLine$ + DO: LOOP UNTIL INKEY$ = "" DO: LOOP UNTIL _KEYHIT = 0 END IF @@ -23829,6 +23869,7 @@ END FUNCTION '$INCLUDE:'utilities\type.bas' '$INCLUDE:'utilities\give_error.bas' '$INCLUDE:'utilities\format.bas' +'$include:'utilities\terminal.bas' '$INCLUDE:'emit\logging.bas' DEFLNG A-Z diff --git a/source/utilities/terminal.bas b/source/utilities/terminal.bas new file mode 100644 index 000000000..0b7ba875a --- /dev/null +++ b/source/utilities/terminal.bas @@ -0,0 +1,47 @@ +' This function finds a usable terminal installed on Linux and provides the +' required configuration for it. This allows the terminal to display $CONSOLE +' programs and logging if requested. +' +' The user can replace the result with their own configuration, this is just a +' best effort to find a working default. +FUNCTION findWorkingTerminal$() + DIM Exes$(7), Formats$(7) + Exes$(1) = "gnome-terminal": Formats$(1) = "-- $$ $@" + Exes$(2) = "konsole": Formats$(2) = "-e $$ $@" + Exes$(3) = "lxterminal": Formats$(3) = "-e $$ $@" + Exes$(4) = "mate-terminal": Formats$(4) = "-x $$ $@" + Exes$(5) = "xfce4-terminal": Formats$(5) = "-x $$ $@" + Exes$(6) = "urxvt": Formats$(6) = "-e $$ $@" + Exes$(7) = "xterm": Formats$(7) = "-e $$ $@" + + FOR i = 1 TO UBOUND(Exes$) + ret& = SHELL("command -v " + CHR$(34) + Exes$(i) + CHR$(34) + " >/dev/null 2>&1") + + IF ret& = 0 THEN + findWorkingTerminal$ = Exes$(i) + " " + Formats$(i) + EXIT FUNCTION + END IF + NEXT + + findWorkingTerminal$ = "" +END FUNCTION + +SUB generateMacOSLogScript(exe AS STRING, handler AS STRING, scopes AS STRING, cmdstr AS STRING, script AS STRING) + ON ERROR GOTO _NEWHANDLER qberror_test + KILL script + ON ERROR GOTO _LASTHANDLER + + _DELAY .01 + + ff = FREEFILE + OPEN script FOR OUTPUT AS #ff + + PRINT #ff, "export QB64PE_LOG_HANDLERS="; handler; _CHR_LF; + PRINT #ff, "export QB64PE_LOG_SCOPES="; _CHR_QUOTE; scopes; _CHR_QUOTE; _CHR_LF; + PRINT #ff, _CHR_QUOTE; exe; _CHR_QUOTE; " "; cmdstr; _CHR_LF; + + CLOSE #ff + + SHELL _HIDE "chmod +x " + _CHR_QUOTE + script + _CHR_QUOTE +END SUB +