<commit_before>###
Rendering of static codemirror editor.

Meant to be efficient to render hundreds
of these on the page at once.
###

{React, ReactDOM, rclass, rtypes}  = require('../smc-react')

misc_page     = require('../misc_page')

misc = require('smc-util/misc')

#{FormGroup, ControlLabel, FormControl, } = require('react-bootstrap')
{Dropdown, MenuItem} = require('react-bootstrap')

{Complete} = require('./complete')

{Cursors} = require('./cursors')

BLURRED_STYLE =
    width         : '100%'
    overflowX     : 'hidden'
    background    : '#f7f7f7'
    lineHeight    : 'normal'
    height        : 'auto'
    fontSize      : 'inherit'
    marginBottom  : 0
    padding       : '4px'
    whiteSpace    : 'pre-wrap'
    wordWrap      : 'break-word'
    wordBreak     : 'normal'
    border        : 0
    paddingLeft   : '4px'

exports.CodeMirrorStatic = rclass
    propTypes:
        actions          : rtypes.object
        id               : rtypes.string.isRequired
        options          : rtypes.immutable.Map.isRequired
        value            : rtypes.string.isRequired
        font_size        : rtypes.number
        cursors          : rtypes.immutable.Map
        complete         : rtypes.immutable.Map
        set_click_coords : rtypes.func.isRequired

    focus: (event) ->
        if not @props.actions?  # read only
            return
        if event.shiftKey
            misc_page.clear_selection()
            @props.actions.select_cell_range(@props.id)
            event.stopPropagation()
            return
        @props.actions.set_mode('edit')
        @props.actions.unselect_all_cells()
        @props.actions.set_cur_id(@props.id)
        @props.set_click_coords({left:event.clientX, top:event.clientY})

    line_number: (key, line, width) ->
        <div key={key} className='CodeMirror-gutter-wrapper'>
            <div style={left:"-#{width+4}px", width:"#{width-9}px"} className='CodeMirror-linenumber CodeMirror-gutter-elt'>
                {line}
            </div>
        </div>

    render_lines: (width) ->
        mode = @props.options.getIn(['mode', 'name']) ? 'python'
        v = []
        line_numbers = !!@props.options.get('lineNumbers')
        line = 1
        if line_numbers
            append_line_number = =>
                v.push(@line_number(v.length, line, width))
                line += 1
            append_line_number()

        last_type = undefined  # used for detecting introspection
        append = (text, type) ->
            if type?
                v.push(<span key={v.length} className={'cm-'+type}>{text}</span>)
                if text.trim().length > 0
                    last_type = type
            else
                v.push(<span key={v.length}>{text}</span>)
            if line_numbers and text == '\n'
                append_line_number()

        CodeMirror.runMode(@props.value, mode, append)
        line_numbers = false; append('\n')

        @props.actions?.set_last_type(@props.id, last_type)
        return v

    render_code: ->
        if @props.options.get('lineNumbers')
            num_lines = @props.value.split('\n').length
            if num_lines < 100
                width = 30
            else if num_lines < 1000
                width = 39
            else if num_lines < 10000
                width = 49
            else # nobody better do this...
                width = 59
            style = misc.merge(misc.copy(BLURRED_STYLE), {paddingLeft: "#{width+4}px"})
        else
            width = 0
            style = BLURRED_STYLE

        <pre
            className = "CodeMirror cm-s-default CodeMirror-wrap"
            style     = {style}
            onClick   = {@focus}>
            {@render_lines(width)}
            {@render_gutter(width)}
        </pre>

    render_gutter: (width) ->
        if @props.options.get('lineNumbers')
            <div className="CodeMirror-gutters">
                <div className="CodeMirror-gutter CodeMirror-linenumbers" style={width:"#{width-1}px"}>
                </div>
            </div>

    render_complete: ->
        if @props.complete?
            if @props.complete.get('matches')?.size > 0
                <Complete
                    complete = {@props.complete}
                    actions  = {@props.actions}
                    id       = {@props.id}
                />

    render_cursors: ->
        if @props.cursors?
            <Cursors cursors = {@props.cursors} />

    render: ->
        <div style={width: '100%', display:'flex', overflow:'auto'}>
            <div style={width: '100%', position:'relative', border:'1px solid rgb(207, 207, 207)', borderRadius: '2px'}>
                {@render_cursors()}
                {@render_code()}
                {@render_complete()}
            </div>
        </div>






<commit_msg>jupyter: copy/select didn't work when cell goes from unfocused to focused<commit_after>###
Rendering of static codemirror editor.

Meant to be efficient to render hundreds
of these on the page at once.
###

{React, ReactDOM, rclass, rtypes}  = require('../smc-react')

misc_page     = require('../misc_page')

misc = require('smc-util/misc')

#{FormGroup, ControlLabel, FormControl, } = require('react-bootstrap')
{Dropdown, MenuItem} = require('react-bootstrap')

{Complete} = require('./complete')

{Cursors} = require('./cursors')

BLURRED_STYLE =
    width         : '100%'
    overflowX     : 'hidden'
    background    : '#f7f7f7'
    lineHeight    : 'normal'
    height        : 'auto'
    fontSize      : 'inherit'
    marginBottom  : 0
    padding       : '4px'
    whiteSpace    : 'pre-wrap'
    wordWrap      : 'break-word'
    wordBreak     : 'normal'
    border        : 0
    paddingLeft   : '4px'

exports.CodeMirrorStatic = rclass
    propTypes:
        actions          : rtypes.object
        id               : rtypes.string.isRequired
        options          : rtypes.immutable.Map.isRequired
        value            : rtypes.string.isRequired
        font_size        : rtypes.number
        cursors          : rtypes.immutable.Map
        complete         : rtypes.immutable.Map
        set_click_coords : rtypes.func.isRequired

    focus: (event) ->
        if not @props.actions?  # read only
            return
        if event.shiftKey
            misc_page.clear_selection()
            @props.actions.select_cell_range(@props.id)
            event.stopPropagation()
            return
        if window.getSelection().toString()
            # User is selected some text in the cell; if we switch to edit mode
            # then the selection would be cleared, which is annoying.  NOTE that
            # this makes the behavior slightly different than official Jupyter.
            return
        @props.actions.set_mode('edit')
        @props.actions.unselect_all_cells()
        @props.actions.set_cur_id(@props.id)
        @props.set_click_coords({left:event.clientX, top:event.clientY})

    line_number: (key, line, width) ->
        <div key={key} className='CodeMirror-gutter-wrapper'>
            <div style={left:"-#{width+4}px", width:"#{width-9}px"} className='CodeMirror-linenumber CodeMirror-gutter-elt'>
                {line}
            </div>
        </div>

    render_lines: (width) ->
        mode = @props.options.getIn(['mode', 'name']) ? 'python'
        v = []
        line_numbers = !!@props.options.get('lineNumbers')
        line = 1
        if line_numbers
            append_line_number = =>
                v.push(@line_number(v.length, line, width))
                line += 1
            append_line_number()

        last_type = undefined  # used for detecting introspection
        append = (text, type) ->
            if type?
                v.push(<span key={v.length} className={'cm-'+type}>{text}</span>)
                if text.trim().length > 0
                    last_type = type
            else
                v.push(<span key={v.length}>{text}</span>)
            if line_numbers and text == '\n'
                append_line_number()

        CodeMirror.runMode(@props.value, mode, append)
        line_numbers = false; append('\n')

        @props.actions?.set_last_type(@props.id, last_type)
        return v

    render_code: ->
        if @props.options.get('lineNumbers')
            num_lines = @props.value.split('\n').length
            if num_lines < 100
                width = 30
            else if num_lines < 1000
                width = 39
            else if num_lines < 10000
                width = 49
            else # nobody better do this...
                width = 59
            style = misc.merge(misc.copy(BLURRED_STYLE), {paddingLeft: "#{width+4}px"})
        else
            width = 0
            style = BLURRED_STYLE

        <pre
            className = "CodeMirror cm-s-default CodeMirror-wrap"
            style     = {style}
            onClick   = {@focus}>
            {@render_lines(width)}
            {@render_gutter(width)}
        </pre>

    render_gutter: (width) ->
        if @props.options.get('lineNumbers')
            <div className="CodeMirror-gutters">
                <div className="CodeMirror-gutter CodeMirror-linenumbers" style={width:"#{width-1}px"}>
                </div>
            </div>

    render_complete: ->
        if @props.complete?
            if @props.complete.get('matches')?.size > 0
                <Complete
                    complete = {@props.complete}
                    actions  = {@props.actions}
                    id       = {@props.id}
                />

    render_cursors: ->
        if @props.cursors?
            <Cursors cursors = {@props.cursors} />

    render: ->
        <div style={width: '100%', display:'flex', overflow:'auto'}>
            <div style={width: '100%', position:'relative', border:'1px solid rgb(207, 207, 207)', borderRadius: '2px'}>
                {@render_cursors()}
                {@render_code()}
                {@render_complete()}
            </div>
        </div>







{'fraction_non_alphanumeric': 0.12454945935122147, 'fraction_numerical': 0.011213456147376852, 'mean_word_length': 1.7240250886283066, 'pattern_counts': {'":': 0, '<': 49, '<?xml version=': 0, '>': 67, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6336533', 'n_tokens_mistral': 3045, 'n_tokens_neox': 2843, 'n_words': 609}