mirror of
https://github.com/Eugeny/tabby.git
synced 2025-06-10 22:50:04 +00:00
This commit is contained in:
parent
cfa29acb5a
commit
4aa824d725
@ -261,7 +261,9 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
|
|||||||
case 'search':
|
case 'search':
|
||||||
this.showSearchPanel = true
|
this.showSearchPanel = true
|
||||||
setImmediate(() => {
|
setImmediate(() => {
|
||||||
this.element.nativeElement.querySelector('.search-input').focus()
|
const input = this.element.nativeElement.querySelector('.search-input')
|
||||||
|
input?.focus()
|
||||||
|
input?.select()
|
||||||
})
|
})
|
||||||
break
|
break
|
||||||
case 'pane-focus-all':
|
case 'pane-focus-all':
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
flex: auto;
|
flex: auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
overflow: hidden;
|
// overflow: hidden;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
&> .content {
|
&> .content {
|
||||||
|
@ -1,27 +1,31 @@
|
|||||||
input.search-input.form-control(
|
.input-group
|
||||||
type='text',
|
input.search-input.form-control(
|
||||||
[(ngModel)]='query',
|
type='text',
|
||||||
(ngModelChange)='onQueryChange()',
|
[(ngModel)]='query',
|
||||||
[class.text-danger]='notFound',
|
(ngModelChange)='onQueryChange()',
|
||||||
(click)='$event.stopPropagation()',
|
[class.text-danger]='state.resultCount == 0',
|
||||||
(keyup.enter)='findPrevious()',
|
(click)='$event.stopPropagation()',
|
||||||
(keyup.esc)='close.emit()',
|
(keyup.enter)='findPrevious()',
|
||||||
[placeholder]='"Search"|translate'
|
(keyup.esc)='close.emit()',
|
||||||
)
|
[placeholder]='"Search"|translate'
|
||||||
|
)
|
||||||
|
.input-group-append(*ngIf='state.resultCount > 0')
|
||||||
|
.input-group-text.result-counter {{state.resultIndex + 1}} / {{state.resultCount}}
|
||||||
|
|
||||||
button.btn.btn-link(
|
ng-container(*ngIf='state.resultCount > 0')
|
||||||
(click)='findPrevious()',
|
button.btn.btn-link(
|
||||||
ngbTooltip='Search up',
|
(click)='findPrevious()',
|
||||||
placement='bottom',
|
ngbTooltip='Search up',
|
||||||
[fastHtmlBind]='icons.arrowUp'
|
placement='bottom',
|
||||||
)
|
[fastHtmlBind]='icons.arrowUp'
|
||||||
|
)
|
||||||
|
|
||||||
button.btn.btn-link(
|
button.btn.btn-link(
|
||||||
(click)='findNext()',
|
(click)='findNext()',
|
||||||
ngbTooltip='Search down',
|
ngbTooltip='Search down',
|
||||||
placement='bottom',
|
placement='bottom',
|
||||||
[fastHtmlBind]='icons.arrowDown'
|
[fastHtmlBind]='icons.arrowDown'
|
||||||
)
|
)
|
||||||
|
|
||||||
.mr-2
|
.mr-2
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
:host {
|
:host {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
width: 400px;
|
width: 600px;
|
||||||
right: 40px;
|
right: 40px;
|
||||||
z-index: 5;
|
z-index: 5;
|
||||||
border-radius: 0 0 5px 5px;
|
border-radius: 0 0 5px 5px;
|
||||||
@ -15,3 +15,8 @@
|
|||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.result-counter {
|
||||||
|
font-size: 0.7rem;
|
||||||
|
opacity: .5;
|
||||||
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Component, Input, Output, EventEmitter } from '@angular/core'
|
import { Component, Input, Output, EventEmitter } from '@angular/core'
|
||||||
import { Frontend, SearchOptions } from '../frontends/frontend'
|
import { Frontend, SearchOptions, SearchState } from '../frontends/frontend'
|
||||||
import { ConfigService, NotificationsService, TranslateService } from 'tabby-core'
|
import { ConfigService, NotificationsService, TranslateService } from 'tabby-core'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -10,7 +10,7 @@ import { ConfigService, NotificationsService, TranslateService } from 'tabby-cor
|
|||||||
export class SearchPanelComponent {
|
export class SearchPanelComponent {
|
||||||
@Input() query: string
|
@Input() query: string
|
||||||
@Input() frontend: Frontend
|
@Input() frontend: Frontend
|
||||||
notFound = false
|
state: SearchState = { resultCount: 0 }
|
||||||
options: SearchOptions = {
|
options: SearchOptions = {
|
||||||
incremental: true,
|
incremental: true,
|
||||||
...this.config.store.terminal.searchOptions,
|
...this.config.store.terminal.searchOptions,
|
||||||
@ -34,7 +34,7 @@ export class SearchPanelComponent {
|
|||||||
) { }
|
) { }
|
||||||
|
|
||||||
onQueryChange (): void {
|
onQueryChange (): void {
|
||||||
this.notFound = false
|
this.state = { resultCount: 0 }
|
||||||
this.findPrevious(true)
|
this.findPrevious(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,8 +42,8 @@ export class SearchPanelComponent {
|
|||||||
if (!this.query) {
|
if (!this.query) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!this.frontend.findNext(this.query, { ...this.options, incremental: incremental || undefined })) {
|
this.state = this.frontend.findNext(this.query, { ...this.options, incremental: incremental || undefined })
|
||||||
this.notFound = true
|
if (!this.state.resultCount) {
|
||||||
this.notifications.notice(this.translate.instant('Not found'))
|
this.notifications.notice(this.translate.instant('Not found'))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -52,8 +52,8 @@ export class SearchPanelComponent {
|
|||||||
if (!this.query) {
|
if (!this.query) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!this.frontend.findPrevious(this.query, { ...this.options, incremental: incremental || undefined })) {
|
this.state = this.frontend.findPrevious(this.query, { ...this.options, incremental: incremental || undefined })
|
||||||
this.notFound = true
|
if (!this.state.resultCount) {
|
||||||
this.notifications.notice(this.translate.instant('Not found'))
|
this.notifications.notice(this.translate.instant('Not found'))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,11 @@ export interface SearchOptions {
|
|||||||
incremental?: true
|
incremental?: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SearchState {
|
||||||
|
resultIndex?: number
|
||||||
|
resultCount: number
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extend to add support for a different VT frontend implementation
|
* Extend to add support for a different VT frontend implementation
|
||||||
*/
|
*/
|
||||||
@ -75,8 +80,8 @@ export abstract class Frontend {
|
|||||||
abstract configure (): void
|
abstract configure (): void
|
||||||
abstract setZoom (zoom: number): void
|
abstract setZoom (zoom: number): void
|
||||||
|
|
||||||
abstract findNext (term: string, searchOptions?: SearchOptions): boolean
|
abstract findNext (term: string, searchOptions?: SearchOptions): SearchState
|
||||||
abstract findPrevious (term: string, searchOptions?: SearchOptions): boolean
|
abstract findPrevious (term: string, searchOptions?: SearchOptions): SearchState
|
||||||
abstract cancelSearch (): void
|
abstract cancelSearch (): void
|
||||||
|
|
||||||
abstract saveState (): any
|
abstract saveState (): any
|
||||||
|
@ -16,3 +16,13 @@
|
|||||||
.xterm-decoration-overview-ruler {
|
.xterm-decoration-overview-ruler {
|
||||||
right: 6px;
|
right: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.xterm-find-result-decoration {
|
||||||
|
box-sizing: content-box;
|
||||||
|
|
||||||
|
border-radius: 3px;
|
||||||
|
padding: 2px;
|
||||||
|
margin: -2px;
|
||||||
|
outline: 2px solid yellow;
|
||||||
|
backdrop-filter: contrast(2);
|
||||||
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Injector } from '@angular/core'
|
import { Injector } from '@angular/core'
|
||||||
import { ConfigService, getCSSFontFamily, HostAppService, HotkeysService, Platform, PlatformService } from 'tabby-core'
|
import { ConfigService, getCSSFontFamily, HostAppService, HotkeysService, Platform, PlatformService } from 'tabby-core'
|
||||||
import { Frontend, SearchOptions } from './frontend'
|
import { Frontend, SearchOptions, SearchState } from './frontend'
|
||||||
import { takeUntil } from 'rxjs'
|
import { takeUntil } from 'rxjs'
|
||||||
import { Terminal, ITheme } from 'xterm'
|
import { Terminal, ITheme } from 'xterm'
|
||||||
import { FitAddon } from 'xterm-addon-fit'
|
import { FitAddon } from 'xterm-addon-fit'
|
||||||
@ -34,6 +34,7 @@ export class XTermFrontend extends Frontend {
|
|||||||
private configuredTheme: ITheme = {}
|
private configuredTheme: ITheme = {}
|
||||||
private copyOnSelect = false
|
private copyOnSelect = false
|
||||||
private search = new SearchAddon()
|
private search = new SearchAddon()
|
||||||
|
private searchState: SearchState = { resultCount: 0 }
|
||||||
private fitAddon = new FitAddon()
|
private fitAddon = new FitAddon()
|
||||||
private serializeAddon = new SerializeAddon()
|
private serializeAddon = new SerializeAddon()
|
||||||
private ligaturesAddon?: LigaturesAddon
|
private ligaturesAddon?: LigaturesAddon
|
||||||
@ -178,6 +179,10 @@ export class XTermFrontend extends Frontend {
|
|||||||
|
|
||||||
this.xterm.loadAddon(this.search)
|
this.xterm.loadAddon(this.search)
|
||||||
|
|
||||||
|
this.search.onDidChangeResults(state => {
|
||||||
|
this.searchState = state ?? { resultCount: 0 }
|
||||||
|
})
|
||||||
|
|
||||||
window.addEventListener('resize', this.resizeHandler)
|
window.addEventListener('resize', this.resizeHandler)
|
||||||
|
|
||||||
this.resizeHandler()
|
this.resizeHandler()
|
||||||
@ -327,16 +332,30 @@ export class XTermFrontend extends Frontend {
|
|||||||
decorations: {
|
decorations: {
|
||||||
matchOverviewRuler: '#cccc00',
|
matchOverviewRuler: '#cccc00',
|
||||||
activeMatchColorOverviewRuler: '#ffff00',
|
activeMatchColorOverviewRuler: '#ffff00',
|
||||||
|
matchBorder: '#cc0',
|
||||||
|
activeMatchBorder: '#ff0',
|
||||||
|
activeMatchBackground: 'rgba(255, 255, 0, 0.3)',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
findNext (term: string, searchOptions?: SearchOptions): boolean {
|
private wrapSearchResult (result: boolean): SearchState {
|
||||||
return this.search.findNext(term, this.getSearchOptions(searchOptions))
|
if (!result) {
|
||||||
|
return { resultCount: 0 }
|
||||||
|
}
|
||||||
|
return this.searchState
|
||||||
}
|
}
|
||||||
|
|
||||||
findPrevious (term: string, searchOptions?: SearchOptions): boolean {
|
findNext (term: string, searchOptions?: SearchOptions): SearchState {
|
||||||
return this.search.findPrevious(term, this.getSearchOptions(searchOptions))
|
return this.wrapSearchResult(
|
||||||
|
this.search.findNext(term, this.getSearchOptions(searchOptions))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
findPrevious (term: string, searchOptions?: SearchOptions): SearchState {
|
||||||
|
return this.wrapSearchResult(
|
||||||
|
this.search.findPrevious(term, this.getSearchOptions(searchOptions))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
cancelSearch (): void {
|
cancelSearch (): void {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user