package com.intellij.lang.javascript.flex.debug; import com.intellij.openapi.util.io.FileUtil; import com.intellij.util.containers.BidirectionalMap; import gnu.trove.THashMap; import gnu.trove.TIntObjectHashMap; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.Nullable; import java.util.*; public class KnownFilesInfo { private final FlexDebugProcess myFlexDebugProcess; private boolean myUpToDate = false; private final TIntObjectHashMap<BidirectionalMap<String, String>> myWorkerToFilePathToIdMap = new TIntObjectHashMap<>(); private final TIntObjectHashMap<Map<String, Collection<String>>> myWorkerToFileNameToPathsMap = new TIntObjectHashMap<>(); public KnownFilesInfo(final FlexDebugProcess flexDebugProcess) { myFlexDebugProcess = flexDebugProcess; } public void setUpToDate(final boolean upToDate) { myUpToDate = upToDate; } @Nullable public String getFilePathById(final int worker, final String id) { ensureUpToDate(); final BidirectionalMap<String, String> filePathToId = myWorkerToFilePathToIdMap.get(worker); final List<String> paths = filePathToId == null ? null : filePathToId.getKeysByValue(id); return paths != null && paths.size() > 0 ? paths.get(0) : null; } @Nullable public String getIdByFilePath(final String filePath) { ensureUpToDate(); final int worker = 0; // todo calculate correct worker final BidirectionalMap<String, String> filePathToId = myWorkerToFilePathToIdMap.get(worker); return filePathToId == null ? null : filePathToId.get(filePath); } @Nullable public String getIdByFilePathNoUpdate(final String filePath) { final int worker = 0; // todo calculate correct worker final BidirectionalMap<String, String> filePathToId = myWorkerToFilePathToIdMap.get(worker); return filePathToId == null ? null : filePathToId.get(filePath); } @Nullable public Collection<String> getPathsByName(final int worker, final String fileName) { ensureUpToDate(); final Map<String, Collection<String>> fileNameToPaths = myWorkerToFileNameToPathsMap.get(worker); return fileNameToPaths == null ? null : fileNameToPaths.get(fileName); } private void ensureUpToDate() { if (myUpToDate) return; myFlexDebugProcess.sendAndProcessOneCommand( new DebuggerCommand("show files", CommandOutputProcessingType.SPECIAL_PROCESSING, VMState.SUSPENDED, VMState.SUSPENDED) { @Override CommandOutputProcessingMode onTextAvailable(@NonNls String s) { processShowFilesResult(new StringTokenizer(s, "\r\n")); return CommandOutputProcessingMode.DONE; } }, null); myUpToDate = true; } private void processShowFilesResult(StringTokenizer tokenizer) { //2 C:\work\flex_projects\MP3Worker\src\Workers.as, Workers.as //2 C:\work\flex_projects\MP3Worker\src\Workers.as, Workers.as (Main Thread) //1 C:\work\flex_projects\MP3Worker\src\BackWorker.as, BackWorker.as (Worker 1) while (tokenizer.hasMoreTokens()) { final String line = tokenizer.nextToken().trim(); final int spaceIndex = line.indexOf(' '); final int commaIndex = line.indexOf(", "); if (spaceIndex == -1 || commaIndex == -1) { FlexDebugProcess.log("Unexpected string format:" + line); continue; } final String id = line.substring(0, spaceIndex); String fullPath = FileUtil.toSystemIndependentName(line.substring(spaceIndex + 1, commaIndex)); int markerIndex = fullPath.indexOf("/frameworks/projects/"); if (markerIndex != -1 && fullPath.indexOf("/src/", markerIndex) > 0) { fullPath = myFlexDebugProcess.getAppSdkHome() + fullPath.substring(markerIndex); } final int nextSpaceIndex = line.indexOf(' ', commaIndex + 2); final String shortName = nextSpaceIndex > 0 ? line.substring(commaIndex + 2, nextSpaceIndex) : line.substring(commaIndex); int worker = 0; if (nextSpaceIndex > 0) { if ("(Main Thread)".equals(line.substring(nextSpaceIndex + 1))) { worker = 0; } else if (line.substring(nextSpaceIndex + 1).startsWith("(Worker ") && line.endsWith(")")) { try { worker = Integer.parseInt(line.substring(nextSpaceIndex + 1 + "(Worker ".length(), line.length() - 1)); } catch (NumberFormatException e) { FlexDebugProcess.log("Unexpected string format:" + line); } } else { FlexDebugProcess.log("Unexpected string format:" + line); } } BidirectionalMap<String, String> filePathToIdMap = myWorkerToFilePathToIdMap.get(worker); if (filePathToIdMap == null) { filePathToIdMap = new BidirectionalMap<>(); myWorkerToFilePathToIdMap.put(worker, filePathToIdMap); } filePathToIdMap.put(fullPath, id); Map<String, Collection<String>> fileNameToPaths = myWorkerToFileNameToPathsMap.get(worker); if (fileNameToPaths == null) { fileNameToPaths = new THashMap<>(); myWorkerToFileNameToPathsMap.put(worker, fileNameToPaths); } addToMap(fileNameToPaths, shortName, fullPath); } } private static <K, T> void addToMap(final Map<K, Collection<T>> map, final K key, final T valueCollectionElement) { Collection<T> valueCollection = map.get(key); if (valueCollection == null) { valueCollection = new ArrayList<>(1); map.put(key, valueCollection); } if (!valueCollection.contains(valueCollectionElement)) { valueCollection.add(valueCollectionElement); } } }