Source:
<code>private void injectContextMenuHandler() { docDisplay_.addContextMenuHandler((event) -> { if (docDisplay_.hasSelection()) return; Position pos = docDisplay_.getCursorPosition(); Position endOfLine = Position.create(docDisplay_.getLine(pos.getRow()).length(), pos.getColumn()); Iterable<Range> wordSource = docDisplay_.getWords( docDisplay_.getFileType().getTokenPredicate(), docDisplay_.getFileType().getCharPredicate(), pos, endOfLine); Iterator<Range> wordsIterator = wordSource.iterator(); if (!wordsIterator.hasNext()) return; Range wordRange = wordsIterator.next(); String word = docDisplay_.getTextForRange(wordRange); if (word.length() < 2 || typoSpellChecker_.checkSpelling(word)) return; final ToolbarPopupMenu menu = new ToolbarPopupMenu(); String[] suggestions = typoSpellChecker_.suggestionList(word); event.preventDefault(); event.stopPropagation(); for (String suggestion : suggestions) { MenuItem suggestionItem = new MenuItem( AppCommand.formatMenuLabel(null, suggestion, ""), true, () -> { docDisplay_.replaceRange(wordRange, suggestion); docDisplay_.removeMarkersAtCursorPosition(); }); menu.addItem(suggestionItem); } if (suggestions.length > 0) menu.addSeparator(); MenuItem addToDictionaryItem = new MenuItem( AppCommand.formatMenuLabel(RES.addToDictIcon(), "Add to user dictionary", ""), true, () -> { typoSpellChecker_.addToUserDictionary(word); docDisplay_.removeMarkersAtCursorPosition(); }); menu.addItem(addToDictionaryItem); <START> menu.setPopupPositionAndShow((offWidth, offHeight) -> { <END> menu.setPopupPosition(event.getNativeEvent().getClientX(), event.getNativeEvent().getClientY()); }); }); }</code><technical_language>Do need account for boundaries of editor here? (thinking e.g. source windows boundaries of editor means clipped)</technical_language>

Target:
private void injectContextMenuHandler() { docDisplay_.addContextMenuHandler((event) -> { if (docDisplay_.hasSelection()) return; Position pos = docDisplay_.getCursorPosition(); Position endOfLine = Position.create(pos.getRow()+1, 0); Iterable<Range> wordSource = docDisplay_.getWords( docDisplay_.getFileType().getTokenPredicate(), docDisplay_.getFileType().getCharPredicate(), pos, endOfLine); Iterator<Range> wordsIterator = wordSource.iterator(); if (!wordsIterator.hasNext()) return; Range wordRange = wordsIterator.next(); String word = docDisplay_.getTextForRange(wordRange); if (word.length() < 2 || typoSpellChecker_.checkSpelling(word)) return; final ToolbarPopupMenu menu = new ToolbarPopupMenu(); String[] suggestions = typoSpellChecker_.suggestionList(word); event.preventDefault(); event.stopPropagation(); int i = 0; for (String suggestion : suggestions) { if (i >= MAX_SUGGESTIONS) break; MenuItem suggestionItem = new MenuItem( AppCommand.formatMenuLabel(null, suggestion, ""), true, () -> { docDisplay_.replaceRange(wordRange, suggestion); docDisplay_.removeMarkersAtCursorPosition(); }); menu.addItem(suggestionItem); i++; } if (suggestions.length > 0) menu.addSeparator(); MenuItem addToDictionaryItem = new MenuItem( AppCommand.formatMenuLabel(RES.addToDictIcon(), "Add to user dictionary", ""), true, () -> { typoSpellChecker_.addToUserDictionary(word); docDisplay_.removeMarkersAtCursorPosition(); }); menu.addItem(addToDictionaryItem); menu.setPopupPositionAndShow((offWidth, offHeight) -> { int clientX = event.getNativeEvent().getClientX(); int clientY = event.getNativeEvent().getClientY(); int menuX = Math.min(clientX, Window.getClientWidth() - offWidth); int menuY = Math.min(clientY, Window.getClientHeight() - offHeight); menu.setPopupPosition(menuX, menuY); }); }); }