private void handleLongDurationChange() {
		// Skip if parser is not ready yet.
		if (parser == null)
			return;

		// Skip if we already shut down the pool.
		if (parseThreadPool.isShutdown())
			return;

		// Cancel last parse future if not complete
		if (lastFuture != null && !lastFuture.isDone())
			lastFuture.cancel(true);

		// Do parsing on BG thread, it can be slower on complex inputs.
		lastFuture = parseThreadPool.submit(ThreadUtil.wrap(() -> {
			String text = editor.getText();

			// Skip if the source hasn't changed since the last time.
			// This may occur when the user inserts some text, then removes it, resulting in the original text again.
			int textHash = text.hashCode();
			if (lastSourceHash == textHash) {
				logger.debugging(l -> l.info("Skipping AST parse, source hash has not changed"));
				return;
			}
			lastSourceHash = textHash;

			// When code changes are made we want to notify users that while an existing unit is available
			// an up-to-date one is still pending.
			if (unit != null)
				astAvailabilityButton.setNewParseInProgress();


			// Parse the current source
			long start = System.currentTimeMillis();
			String classNameEsc = EscapeUtil.escapeStandardAndUnicodeWhitespace(className);
			logger.debugging(l -> l.info("Starting AST parse..."));
			try {
				CompilationUnitModel resultingUnit = parser.parse(text);
				long diffMs = (System.currentTimeMillis() - start);
				if (resultingUnit.getDeclaredClasses().isEmpty()) {
					unit = null;
					resolver = null;

					logger.warn("Could not create Java AST model from source of: {} after {}ms", classNameEsc, diffMs);
					astAvailabilityButton.setUnavailable();
				} else {
					unit = resultingUnit;
					resolver = astService.newJavaResolver(workspace, resultingUnit);
					resolver.setClassContext(getPath().getValue());

					logger.debugging(l -> l.info("AST parsed successfully, took {}ms", diffMs));
					astAvailabilityButton.setAvailable();

					// Run queued tasks
					if (queuedSelectionTask != null) queuedSelectionTask.run();
				}
			} catch (Throwable ex) {
				long diffMs = (System.currentTimeMillis() - start);
				logger.warn("Parse error from source of: {} after {}ms", classNameEsc, diffMs, ex);
				astAvailabilityButton.setParserError(ex);
			}

			// Wipe offset map now that we have a new AST
			offsetMap.clear();
		}));
	}
Handle a full reparse of the source, updating the {@link #unit}.
recaf-ui/src/main/java/software/coley/recaf/ui/control/richtext/source/JavaContextActionSupport.java