/* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import m from 'mithril'; import {globals} from './globals'; interface ArgumentPopupArgs { onArgumentChange: (arg: string) => void; knownArguments: string[]; } function longestString(array: string[]): string { if (array.length === 0) { return ''; } let answer = array[0]; for (let i = 1; i < array.length; i++) { if (array[i].length > answer.length) { answer = array[i]; } } return answer; } // Component rendering popup for entering an argument name to use as a pivot. export class ArgumentPopup implements m.ClassComponent { argument = ''; setArgument(attrs: ArgumentPopupArgs, arg: string) { this.argument = arg; attrs.onArgumentChange(arg); globals.rafScheduler.scheduleFullRedraw(); } renderMatches(attrs: ArgumentPopupArgs): m.Child[] { const result: m.Child[] = []; for (const option of attrs.knownArguments) { // Would be great to have smarter fuzzy matching, but in the meantime // simple substring check should work fine. const index = option.indexOf(this.argument); if (index === -1) { continue; } if (result.length === 10) { break; } result.push( m('div', { onclick: () => { this.setArgument(attrs, option); }, }, option.substring(0, index), // Highlight the matching part with bold font m('strong', this.argument), option.substring(index + this.argument.length))); } return result; } view({attrs}: m.Vnode): m.Child { return m( '.name-completion', m('input', { oncreate: (vnode: m.VnodeDOM) => (vnode.dom as HTMLInputElement).focus(), oninput: (e: Event) => { const input = e.target as HTMLInputElement; this.setArgument(attrs, input.value); }, value: this.argument, }), m('.arguments-popup-sizer', longestString(attrs.knownArguments)), this.renderMatches(attrs)); } }