1- import { OverType } from '../../overtype/mock-overtype'
1+ import hljs from 'highlight.js'
2+ import { logger } from '../../lib/logger'
3+ import OverType , { type OverTypeInstance } from '../../overtype/overtype'
24import type { CommentEnhancer , CommentSpot } from '../enhancer'
35
46const GITHUB_SPOT_TYPES = [
7+ 'GH_PR_ADD_COMMENT' ,
8+ /* TODO
59 'GH_ISSUE_NEW',
610 'GH_PR_NEW',
711 'GH_ISSUE_ADD_COMMENT',
8- 'GH_PR_ADD_COMMENT' ,
9- /* TODO
1012 'GH_ISSUE_EDIT_COMMENT',
1113 'GH_PR_EDIT_COMMENT',
1214 'GH_PR_CODE_COMMENT',
@@ -15,95 +17,95 @@ const GITHUB_SPOT_TYPES = [
1517
1618export type GitHubSpotType = ( typeof GITHUB_SPOT_TYPES ) [ number ]
1719
18- export interface GitHubSpot extends CommentSpot {
20+ export interface GitHubAddCommentSpot extends CommentSpot {
1921 type : GitHubSpotType // Override to narrow from string to specific union
2022 domain : string
2123 slug : string // owner/repo
22- number ? : number | undefined // issue/PR number, undefined for new issues and PRs
24+ number : number // issue/PR number, undefined for new issues and PRs
2325}
2426
25- export class GitHubEnhancer implements CommentEnhancer < GitHubSpot > {
27+ export class GitHubAddCommentEnhancer implements CommentEnhancer < GitHubAddCommentSpot > {
2628 forSpotTypes ( ) : string [ ] {
2729 return [ ...GITHUB_SPOT_TYPES ]
2830 }
2931
30- tryToEnhance ( textarea : HTMLTextAreaElement ) : [ OverType , GitHubSpot ] | null {
31- // Only handle GitHub domains
32- if ( ! window . location . hostname . includes ( 'github' ) ) {
32+ tryToEnhance ( textarea : HTMLTextAreaElement ) : [ OverTypeInstance , GitHubAddCommentSpot ] | null {
33+ // Only handle github.com domains TODO: identify GitHub Enterprise somehow
34+ if ( window . location . hostname !== 'github.com' ) {
3335 return null
3436 }
3537
36- const pathname = window . location . pathname
37-
3838 // Parse GitHub URL structure: /owner/repo/issues/123 or /owner/repo/pull/456
39- const match = pathname . match ( / ^ \/ ( [ ^ / ] + ) \/ ( [ ^ / ] + ) (?: \/ ( i s s u e s | p u l l ) \/ ( \d + ) ) ? / )
40- if ( ! match ) return null
39+ logger . debug ( `${ this . constructor . name } examing url` , window . location . pathname )
4140
42- const [ , owner , repo , urlType , numberStr ] = match
41+ const match = window . location . pathname . match ( / ^ \/ ( [ ^ / ] + ) \/ ( [ ^ / ] + ) (?: \/ p u l l \/ ( \d + ) ) / )
42+ logger . debug ( `${ this . constructor . name } found match` , window . location . pathname )
43+ if ( ! match ) return null
44+ const [ , owner , repo , numberStr ] = match
4345 const slug = `${ owner } /${ repo } `
44- const number = numberStr ? parseInt ( numberStr , 10 ) : undefined
45-
46- // Determine comment type
47- let type : GitHubSpotType
48-
49- if ( pathname . includes ( '/issues/new' ) ) {
50- type = 'GH_ISSUE_NEW'
51- } else if ( pathname . includes ( '/compare/' ) || pathname . endsWith ( '/compare' ) ) {
52- type = 'GH_PR_NEW'
53- } else if ( urlType && number ) {
54- if ( urlType === 'issues' ) {
55- type = 'GH_ISSUE_ADD_COMMENT'
56- } else {
57- type = 'GH_PR_ADD_COMMENT'
58- }
59- } else {
60- return null
61- }
46+ const number = parseInt ( numberStr ! , 10 )
6247
63- // Generate unique key based on context
64- let unique_key = `github:${ slug } `
65- if ( number ) {
66- unique_key += `:${ urlType } :${ number } `
67- } else {
68- unique_key += ':new'
69- }
48+ const unique_key = `github.com:${ slug } :${ number } `
7049
71- const spot : GitHubSpot = {
72- domain : window . location . hostname ,
50+ const spot : GitHubAddCommentSpot = {
51+ domain : 'github.com' ,
7352 number,
7453 slug,
75- type,
54+ type : 'GH_PR_ADD_COMMENT' ,
7655 unique_key,
7756 }
78- const overtype = new OverType ( textarea )
79- return [ overtype , spot ]
57+ return [ this . createOvertypeFor ( textarea ) , spot ]
58+ }
59+
60+ private createOvertypeFor ( ghCommentBox : HTMLTextAreaElement ) : OverTypeInstance {
61+ OverType . setCodeHighlighter ( hljsHighlighter )
62+ const overtypeContainer = this . modifyDOM ( ghCommentBox )
63+ return new OverType ( overtypeContainer , {
64+ autoResize : true ,
65+ minHeight : '102px' ,
66+ padding : 'var(--base-size-8)' ,
67+ placeholder : 'Add your comment here...' ,
68+ } ) [ 0 ] !
69+ }
70+
71+ private modifyDOM ( overtypeInput : HTMLTextAreaElement ) : HTMLElement {
72+ overtypeInput . classList . add ( 'overtype-input' )
73+ const overtypePreview = document . createElement ( 'div' )
74+ overtypePreview . classList . add ( 'overtype-preview' )
75+ overtypeInput . insertAdjacentElement ( 'afterend' , overtypePreview )
76+ const overtypeWrapper = overtypeInput . parentElement ! . closest ( 'div' ) !
77+ overtypeWrapper . classList . add ( 'overtype-wrapper' )
78+ overtypeInput . placeholder = 'Add your comment here...'
79+ const overtypeContainer = overtypeWrapper . parentElement ! . closest ( 'div' ) !
80+ overtypeContainer . classList . add ( 'overtype-container' )
81+ return overtypeContainer . parentElement ! . closest ( 'div' ) !
8082 }
8183
82- tableTitle ( spot : GitHubSpot ) : string {
84+ tableTitle ( spot : GitHubAddCommentSpot ) : string {
8385 const { slug, number } = spot
84- if ( number ) {
85- return `Comment on ${ slug } #${ number } `
86- }
87- return `New ${ window . location . pathname . includes ( '/issues/' ) ? 'issue' : 'PR' } in ${ slug } `
86+ return `${ slug } PR #${ number } `
8887 }
8988
90- tableIcon ( spot : GitHubSpot ) : string {
91- switch ( spot . type ) {
92- case 'GH_ISSUE_NEW' :
93- case 'GH_ISSUE_ADD_COMMENT' :
94- return '🐛' // Issue icon
95- case 'GH_PR_NEW' :
96- case 'GH_PR_ADD_COMMENT' :
97- return '🔄' // PR icon
98- }
89+ tableIcon ( _ : GitHubAddCommentSpot ) : string {
90+ return '🔄' // PR icon TODO: icon urls in /public
91+ }
92+
93+ buildUrl ( spot : GitHubAddCommentSpot ) : string {
94+ return `https://${ spot . domain } /${ spot . slug } /pull/${ spot . number } `
9995 }
96+ }
10097
101- buildUrl ( spot : GitHubSpot ) : string {
102- const baseUrl = `https://${ spot . domain } /${ spot . slug } `
103- if ( spot . number ) {
104- const type = spot . type . indexOf ( 'ISSUE' ) ? 'issues' : 'pull'
105- return `${ baseUrl } /${ type } /${ spot . number } `
98+ function hljsHighlighter ( code : string , language : string ) {
99+ try {
100+ if ( language && hljs . getLanguage ( language ) ) {
101+ const result = hljs . highlight ( code , { language } )
102+ return result . value
103+ } else {
104+ const result = hljs . highlightAuto ( code )
105+ return result . value
106106 }
107- return baseUrl
107+ } catch ( error ) {
108+ console . warn ( 'highlight.js highlighting failed:' , error )
109+ return code
108110 }
109111}
0 commit comments