Add wIRC main scrollback, route services to it, remember window bounds, bump to 0.1.7
wIRC main scrollback - The main window now has a "Server messages" scrollback using the same rendering and stick-to-bottom code as channel windows (extracted from ChannelScreen into a shared MessageScrollback composable). - MOTD, numerics, errors, connection status, user modes, INVITE, ERROR, non-ACTION CTCP requests and notices/messages from services (NickServ, ChanServ, *Serv, Global, ...) and the server go there. Its history persists like any other buffer (history/wirc-main__main.json). - Unread indicator: lines arriving while the main window is unfocused show as "N new" next to the label and in the window title/taskbar. Private messages and /whois - A PM or notice from a real user opens its query window, and reopens it if it was closed. Services and the server no longer open windows. - /whois <nick> sends WHOIS and shows the formatted reply in the window it was typed in, or in wIRC main if that window has since closed. - /me now sends a proper CTCP ACTION (the \x01 wrapper was missing). Window position and size - Main, channel and PM windows remember position and size in window_prefs.json under the existing "<serverId>__<name>" key (main uses "wirc-main__main"). The new windowX/windowY/windowWidth/ windowHeight fields are optional, so older files still load. - A saved position is only used if the window's title strip is on a connected monitor; otherwise, and for windows with no saved position, windows cascade from the primary screen's top-left with a 32dp offset. - window_prefs.json is now written via a temp file + atomic move. Cleanup - Remove the TEMP DEBUG aliasDebug tracing, ServerRepository.upsert printlns and connmgr-debug printlns. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
242d7a7c42
commit
807903fe0f
@@ -5,13 +5,6 @@ import java.io.File
|
||||
import java.net.URI
|
||||
import java.net.URLEncoder
|
||||
|
||||
// TEMP DEBUG (see task: alias multi-word arguments investigation) - remove once confirmed
|
||||
// fixed. Traces the full alias pipeline: raw input -> matched alias -> substituted target
|
||||
// -> the actual Desktop API call, so a silent failure anywhere in that chain is visible.
|
||||
private fun aliasDebug(msg: String) {
|
||||
println("[alias-debug] $msg")
|
||||
}
|
||||
|
||||
// Name reserved for the app-level /reload command (ChannelWindow.kt handles it directly,
|
||||
// before alias lookup even runs) - kept here too so a line in aliases.txt can never define
|
||||
// an alias that would shadow it.
|
||||
@@ -64,15 +57,9 @@ object AliasRepository {
|
||||
* "reload" name, which this repository never loads as an alias).
|
||||
*/
|
||||
fun tryRunAlias(command: String, args: String): Boolean {
|
||||
aliasDebug("tryRunAlias: command=\"$command\" args=\"$args\"")
|
||||
val key = command.lowercase()
|
||||
if (key == RESERVED_RELOAD) return false
|
||||
val action = aliases[key]
|
||||
if (action == null) {
|
||||
aliasDebug("no alias matched for \"$key\"")
|
||||
return false
|
||||
}
|
||||
aliasDebug("matched \"$key\" -> \"$action\"")
|
||||
val action = aliases[key] ?: return false
|
||||
runAction(action, args)
|
||||
return true
|
||||
}
|
||||
@@ -94,13 +81,12 @@ object AliasRepository {
|
||||
// literal, not a URL delimiter.
|
||||
val substitutedArg = if (type == "url") encodeArgForUrl(args) else args
|
||||
val target = if (rawTarget.contains("{arg}")) rawTarget.replace("{arg}", substitutedArg) else rawTarget
|
||||
aliasDebug("type=\"$type\" rawTarget=\"$rawTarget\" substitutedArg=\"$substitutedArg\" -> target=\"$target\"")
|
||||
if (target.isBlank()) return
|
||||
|
||||
try {
|
||||
when (type) {
|
||||
"path" -> { aliasDebug("Desktop.open(File(\"$target\"))"); Desktop.getDesktop().open(File(target)) }
|
||||
"url" -> { aliasDebug("Desktop.browse(URI(\"$target\"))"); Desktop.getDesktop().browse(URI(target)) }
|
||||
"path" -> Desktop.getDesktop().open(File(target))
|
||||
"url" -> Desktop.getDesktop().browse(URI(target))
|
||||
// Routed through "cmd /c start" (same launch path as double-clicking in
|
||||
// Explorer or the Run dialog) rather than exec'd directly. A direct
|
||||
// ProcessBuilder(target).start() calls CreateProcess, which does NOT honor
|
||||
@@ -110,7 +96,7 @@ object AliasRepository {
|
||||
// would. This also preserves bare-name resolution via Windows' App Paths
|
||||
// registry / PATH - not guaranteed to work for every app, since it depends
|
||||
// on that app having registered itself with Windows.
|
||||
"run" -> { aliasDebug("ProcessBuilder start \"$target\""); ProcessBuilder("cmd", "/c", "start", "\"\"", target).start() }
|
||||
"run" -> ProcessBuilder("cmd", "/c", "start", "\"\"", target).start()
|
||||
else -> println("[AliasRepository] Unknown alias action type '$type' in \"$action\"")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
|
||||
Reference in New Issue
Block a user