_handleAutocompletion() {
    const isSelectionEmpty = this._inputNode.selectionStart === this._inputNode.selectionEnd;
    const hasSelection =
      !isSelectionEmpty && this._inputNode.value.length !== this._inputNode.selectionStart;

    const inputValue = this._inputNode.value;
    const inputSelectionStart = this._inputNode.selectionStart;
    const curValue =
      hasSelection && inputSelectionStart ? inputValue.slice(0, inputSelectionStart) : inputValue;

    const prevValue =
      hasSelection || this.__hadSelectionLastAutofill
        ? this.__prevCboxValueNonSelected
        : this.__prevCboxValue;
    const isEmpty = !curValue;

    /**
     * The filtered list of options that will match in this autocompletion cycle
     * @type {LionOption[]}
     */
    const visibleOptions = [];
    /** Whether autofill (activeIndex/checkedIndex and ) has taken place in this 'cycle' */
    let hasAutoFilled = false;
    const userIntendsInlineAutoFill = this.__computeUserIntendsAutoFill({ prevValue, curValue });
    const isInlineAutoFillCandidate =
      this.autocomplete === 'both' || this.autocomplete === 'inline';
    const autoselect = this._autoSelectCondition();
    const noFilter = this.autocomplete === 'inline' || this.autocomplete === 'none';

    this.formElements.forEach((/** @type {OptionWithFilterFn} */ option, i) => {
      // [1]. Decide whether option should be shown
      const matches = this.matchCondition(option, curValue);
      let show = false;
      if (isEmpty) {
        show = this.showAllOnEmpty;
      } else {
        show = noFilter || matches;
      }

      // [2]. Synchronize ._inputNode value and active descendant with closest match
      if (autoselect && !hasAutoFilled && matches && !option.disabled) {
        const doAutoSelect = () => {
          this.activeIndex = i;
          if (this.selectionFollowsFocus && !this.multipleChoice) {
            this.setCheckedIndex(this.activeIndex);
          }
          hasAutoFilled = true;
        };

        if (userIntendsInlineAutoFill) {
          // We should never directly select when removing chars or starting a new word
          // This leads to bad UX and unwanted syncing of modelValue (based on checkedIndex)
          // and _inputNode.value

          if (isInlineAutoFillCandidate) {
            const textboxValue = this._getTextboxValueFromOption(option);
            const stringValues =
              textboxValue && typeof textboxValue === 'string' && typeof curValue === 'string';
            const beginsWith =
              stringValues && textboxValue.toLowerCase().indexOf(curValue.toLowerCase()) === 0;
            // We only can do proper inline autofilling when the beginning of the word matches
            if (beginsWith) {
              this.__textboxInlineComplete(option);
              doAutoSelect();
            }
          } else {
            doAutoSelect();
          }
        }
      }

      // [3]. Cleanup previous matching states
      if (option.onFilterUnmatch) {
        option.onFilterUnmatch(curValue, prevValue);
      } else {
        this._onFilterUnmatch(option, curValue, prevValue);
      }

      // [4]. Cleanup previous visibility and a11y states
      option.setAttribute('aria-hidden', 'true');
      option.removeAttribute('aria-posinset');
      option.removeAttribute('aria-setsize');

      // [5]. Add options that meet matching criteria
      if (show) {
        visibleOptions.push(option);
        if (option.onFilterMatch) {
          option.onFilterMatch(curValue);
        } else {
          this._onFilterMatch(option, curValue);
        }
      }
    });

    // [6]. Enable a11y, visibility and user interaction for visible options
    const setSize = visibleOptions.length;
    visibleOptions.forEach((option, idx) => {
      option.setAttribute('aria-posinset', `${idx + 1}`);
      option.setAttribute('aria-setsize', `${setSize}`);
      option.removeAttribute('aria-hidden');
    });

    // [7]. If no autofill took place, we are left with the previously matched option; correct this
    if (autoselect && !hasAutoFilled && !this.multipleChoice) {
      // This means there is no match for checkedIndex
      this.setCheckedIndex(-1);
      if (prevValue !== curValue) {
        this.activeIndex = -1;
      }
      this.modelValue = this.parser(inputValue);
    }

    // [8]. These values will help computing autofill intentions next autocomplete cycle
    this.__prevCboxValueNonSelected = curValue;
    // See test 'computation of "user intends autofill" works correctly after autofill'
    this.__prevCboxValue = this._inputNode.value;
    this.__hadSelectionLastAutofill =
      this._inputNode.value.length !== this._inputNode.selectionStart;
    this.__hadUserIntendsInlineAutoFill = userIntendsInlineAutoFill;

    // [9]. Reposition overlay
    if (this._overlayCtrl && this._overlayCtrl._popper) {
      this._overlayCtrl._popper.update();
    }
  }
Handles autocompletion. This entails:
- list: shows a list on keydown character press
- filter: filters list of potential matches according to matchmode or provided matchCondition
- focus: automatically focuses closest match (makes it the activedescendant)
- check: automatically checks/selects closest match when selection-follows-focus is enabled
(this is the default configuration)
- complete: completes the textbox value inline (the 'missing characters' will be added as
selected text)

@protected