@Override
		public void completionSelected(AutocompletionEvent<AssemblyCompletion> ev) {
			if (!(ev.getSelection() instanceof AssemblyInstruction ai)) {
				hints.setText("");
				return;
			}

			Program program = assembler.getProgram();
			if (program == null) {
				hints.setText("");
				return;
			}

			ProgramContext ctx = program.getProgramContext();
			Register ctxReg = ctx.getBaseContextRegister();
			StringBuilder sb = new StringBuilder("""
					<html><style>
					ul.addresses {
					  margin: 0;
					  padding: 0;
					}
					ul.addresses > li {
					  margin: 0;
					  padding: 0;
					  list-style-type: none;
					}
					ul.context {
					  font-family: monospaced;
					  margin: 0 0 0 20px;
					}
					span.addr {
					  font-family: monospaced;
					}
					</style><body width="300px"><ul class="addresses">
					""".formatted(ListingColors.REGISTER.toHexString()));
			boolean displayedAny = false;
			for (Entry<Address, RegisterValue> ent : ai.contextChanges.contextsOut.entrySet()) {
				RegisterValue defVal = ctx.getDefaultDisassemblyContext();
				RegisterValue newVal = defVal.combineValues(ent.getValue());
				RegisterValue curVal =
					defVal.combineValues(ctx.getRegisterValue(ctxReg, ent.getKey()));

				boolean displayedAddress = false;
				for (Register sub : ctxReg.getChildRegisters()) {
					BigInteger newSubVal =
						newVal.getRegisterValue(sub).getUnsignedValueIgnoreMask();
					BigInteger curSubVal =
						curVal.getRegisterValue(sub).getUnsignedValueIgnoreMask();
					if (Objects.equals(curSubVal, newSubVal)) {
						continue;
					}
					if (!displayedAddress) {
						sb.append("""
								<li>At <span class="addr">%s</span></li>
								<ul class="context">
								""".formatted(ent.getKey()));
						displayedAddress = true;
					}
					sb.append("""
							<li>%s := 0x%s</li>
							""".formatted(sub.getName(), newSubVal.toString(16)));
					displayedAny = true;
				}
				if (displayedAddress) {
					sb.append("""
							</ul>
							""");
				}
			}
			if (!displayedAny) {
				hints.setText("");
			}
			sb.append("""
					</ul></body></html>
					""");
			hints.setText(sb.toString());
		}
A customized autocompleter for assembly

<p>
This positions the list at the bottom left of the field(s), and considers the full text of
the linked text boxes when retrieving the prefix. It also delegates the item styling to the
item instances.
Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/assembler/AssemblyDualTextField.java