void (@NotNull String line, @NotNull Key outputType) { if (outputType == ProcessOutputTypes.STDERR) { myVm.logger.warn(line); } if (outputType != ProcessOutputTypes.STDOUT || myShuttingDown) { return; } if (myVm.logger.isTraceEnabled()) myVm.logger.trace(">> " + line); if (myLastOp == null) { WatcherOp watcherOp; try { watcherOp = WatcherOp.valueOf(line); } catch (IllegalArgumentException e) { // `wsl.exe` own error messages are coming in UTF16LE, accompanied by a couple of short tails (decoding artifacts) byte[] raw = line.getBytes(StandardCharsets.UTF_8); if (raw.length > 3 && raw[0] != 0 && raw[2] != 0 && raw[1] + raw[3] == 0) { myVm.logger.warn(new String(raw, StandardCharsets.UTF_16LE)); } else if (!(raw.length == 1 && raw[0] == 0 || raw.length == 2 && raw[0] + raw[1] == 0)) { myVm.logger.error("Illegal watcher command: '" + line + "'", (Throwable)null); } return; } if (watcherOp == WatcherOp.GIVEUP) { notifyOnFailure(myVm.name, IdeCoreBundle.message("watcher.gave.up"), null); } else if (watcherOp == WatcherOp.RESET) { myNotificationSink.notifyReset(Strings.trimEnd(myVm.prefix, '\\')); } else { myLastOp = watcherOp; } } else if (myLastOp == WatcherOp.MESSAGE) { String localized = Objects.requireNonNullElse(IdeCoreBundle.INSTANCE.messageOrNull(line), line); //NON-NLS myVm.logger.warn(localized); notifyOnFailure(myVm.name, localized, NotificationListener.URL_OPENING_LISTENER); myLastOp = null; } else if (myLastOp == WatcherOp.UNWATCHEABLE) { if ("#".equals(line)) { mySettingRoots.decrementAndGet(); processUnwatchable(); myLines.clear(); myLastOp = null; } else { myLines.add(line); } } else { String path = StringUtil.trimEnd(line.replace('\0', '\n'), File.separator); // unescape processChange(path, myLastOp); myLastOp = null; } }